mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-11-04 07:13:28 +01:00 
			
		
		
		
	Added basic logging + increment version
Logging is mainly just for the BG task and errors right now.
This commit is contained in:
		@@ -1,4 +1,6 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/logs_provider.dart';
 | 
				
			||||||
 | 
					import 'package:provider/provider.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ObtainiumError {
 | 
					class ObtainiumError {
 | 
				
			||||||
  late String message;
 | 
					  late String message;
 | 
				
			||||||
@@ -75,6 +77,8 @@ class MultiAppMultiError extends ObtainiumError {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
showError(dynamic e, BuildContext context) {
 | 
					showError(dynamic e, BuildContext context) {
 | 
				
			||||||
 | 
					  Provider.of<LogsProvider>(context, listen: false)
 | 
				
			||||||
 | 
					      .add(e.toString(), level: LogLevels.error);
 | 
				
			||||||
  if (e is String || (e is ObtainiumError && !e.unexpected)) {
 | 
					  if (e is String || (e is ObtainiumError && !e.unexpected)) {
 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(content: Text(e.toString())),
 | 
					      SnackBar(content: Text(e.toString())),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
 | 
				
			|||||||
import 'package:obtainium/custom_errors.dart';
 | 
					import 'package:obtainium/custom_errors.dart';
 | 
				
			||||||
import 'package:obtainium/pages/home.dart';
 | 
					import 'package:obtainium/pages/home.dart';
 | 
				
			||||||
import 'package:obtainium/providers/apps_provider.dart';
 | 
					import 'package:obtainium/providers/apps_provider.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/logs_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/notifications_provider.dart';
 | 
					import 'package:obtainium/providers/notifications_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/settings_provider.dart';
 | 
					import 'package:obtainium/providers/settings_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/source_provider.dart';
 | 
					import 'package:obtainium/providers/source_provider.dart';
 | 
				
			||||||
@@ -15,7 +16,7 @@ import 'package:dynamic_color/dynamic_color.dart';
 | 
				
			|||||||
import 'package:device_info_plus/device_info_plus.dart';
 | 
					import 'package:device_info_plus/device_info_plus.dart';
 | 
				
			||||||
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
 | 
					import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const String currentVersion = '0.7.1';
 | 
					const String currentVersion = '0.7.2';
 | 
				
			||||||
const String currentReleaseTag =
 | 
					const String currentReleaseTag =
 | 
				
			||||||
    'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
 | 
					    'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,12 +24,15 @@ const int bgUpdateCheckAlarmId = 666;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@pragma('vm:entry-point')
 | 
					@pragma('vm:entry-point')
 | 
				
			||||||
Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
 | 
					Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
 | 
				
			||||||
 | 
					  LogsProvider logs = LogsProvider();
 | 
				
			||||||
 | 
					  logs.add('Started BG update check task');
 | 
				
			||||||
  int? ignoreAfterMicroseconds = params?['ignoreAfterMicroseconds'];
 | 
					  int? ignoreAfterMicroseconds = params?['ignoreAfterMicroseconds'];
 | 
				
			||||||
  WidgetsFlutterBinding.ensureInitialized();
 | 
					  WidgetsFlutterBinding.ensureInitialized();
 | 
				
			||||||
  await AndroidAlarmManager.initialize();
 | 
					  await AndroidAlarmManager.initialize();
 | 
				
			||||||
  DateTime? ignoreAfter = ignoreAfterMicroseconds != null
 | 
					  DateTime? ignoreAfter = ignoreAfterMicroseconds != null
 | 
				
			||||||
      ? DateTime.fromMicrosecondsSinceEpoch(ignoreAfterMicroseconds)
 | 
					      ? DateTime.fromMicrosecondsSinceEpoch(ignoreAfterMicroseconds)
 | 
				
			||||||
      : null;
 | 
					      : null;
 | 
				
			||||||
 | 
					  logs.add('Bg update ignoreAfter is $ignoreAfter');
 | 
				
			||||||
  var notificationsProvider = NotificationsProvider();
 | 
					  var notificationsProvider = NotificationsProvider();
 | 
				
			||||||
  await notificationsProvider.notify(checkingUpdatesNotification);
 | 
					  await notificationsProvider.notify(checkingUpdatesNotification);
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -40,15 +44,16 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
 | 
				
			|||||||
    DateTime nextIgnoreAfter = DateTime.now();
 | 
					    DateTime nextIgnoreAfter = DateTime.now();
 | 
				
			||||||
    String? err;
 | 
					    String? err;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
 | 
					      logs.add('Started actual BG update checking');
 | 
				
			||||||
      await appsProvider.checkUpdates(
 | 
					      await appsProvider.checkUpdates(
 | 
				
			||||||
          ignoreAppsCheckedAfter: ignoreAfter, throwErrorsForRetry: true);
 | 
					          ignoreAppsCheckedAfter: ignoreAfter, throwErrorsForRetry: true);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      if (e is RateLimitError || e is SocketException) {
 | 
					      if (e is RateLimitError || e is SocketException) {
 | 
				
			||||||
        AndroidAlarmManager.oneShot(
 | 
					        var remainingMinutes = e is RateLimitError ? e.remainingMinutes : 15;
 | 
				
			||||||
            Duration(minutes: e is RateLimitError ? e.remainingMinutes : 15),
 | 
					        logs.add(
 | 
				
			||||||
            Random().nextInt(pow(2, 31) as int),
 | 
					            'BG update checking encountered a ${e.runtimeType}, will schedule a retry check in $remainingMinutes minutes');
 | 
				
			||||||
            bgUpdateCheck,
 | 
					        AndroidAlarmManager.oneShot(Duration(minutes: remainingMinutes),
 | 
				
			||||||
            params: {
 | 
					            Random().nextInt(pow(2, 31) as int), bgUpdateCheck, params: {
 | 
				
			||||||
          'ignoreAfterMicroseconds': nextIgnoreAfter.microsecondsSinceEpoch
 | 
					          'ignoreAfterMicroseconds': nextIgnoreAfter.microsecondsSinceEpoch
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
@@ -74,7 +79,8 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
 | 
				
			|||||||
    //           silentlyUpdated.map((e) => appsProvider.apps[e]!.app).toList()),
 | 
					    //           silentlyUpdated.map((e) => appsProvider.apps[e]!.app).toList()),
 | 
				
			||||||
    //       cancelExisting: true);
 | 
					    //       cancelExisting: true);
 | 
				
			||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					    logs.add(
 | 
				
			||||||
 | 
					        'BG update checking found ${newUpdates.length} updates - will notify user if needed');
 | 
				
			||||||
    if (newUpdates.isNotEmpty) {
 | 
					    if (newUpdates.isNotEmpty) {
 | 
				
			||||||
      notificationsProvider.notify(UpdateNotification(newUpdates));
 | 
					      notificationsProvider.notify(UpdateNotification(newUpdates));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -85,6 +91,7 @@ Future<void> bgUpdateCheck(int taskId, Map<String, dynamic>? params) async {
 | 
				
			|||||||
    notificationsProvider
 | 
					    notificationsProvider
 | 
				
			||||||
        .notify(ErrorCheckingUpdatesNotification(e.toString()));
 | 
					        .notify(ErrorCheckingUpdatesNotification(e.toString()));
 | 
				
			||||||
  } finally {
 | 
					  } finally {
 | 
				
			||||||
 | 
					    logs.add('Finished BG update check task');
 | 
				
			||||||
    await notificationsProvider.cancel(checkingUpdatesNotification.id);
 | 
					    await notificationsProvider.cancel(checkingUpdatesNotification.id);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -102,7 +109,8 @@ void main() async {
 | 
				
			|||||||
    providers: [
 | 
					    providers: [
 | 
				
			||||||
      ChangeNotifierProvider(create: (context) => AppsProvider()),
 | 
					      ChangeNotifierProvider(create: (context) => AppsProvider()),
 | 
				
			||||||
      ChangeNotifierProvider(create: (context) => SettingsProvider()),
 | 
					      ChangeNotifierProvider(create: (context) => SettingsProvider()),
 | 
				
			||||||
      Provider(create: (context) => NotificationsProvider())
 | 
					      Provider(create: (context) => NotificationsProvider()),
 | 
				
			||||||
 | 
					      Provider(create: (context) => LogsProvider())
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    child: const Obtainium(),
 | 
					    child: const Obtainium(),
 | 
				
			||||||
  ));
 | 
					  ));
 | 
				
			||||||
@@ -124,12 +132,14 @@ class _ObtainiumState extends State<Obtainium> {
 | 
				
			|||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    SettingsProvider settingsProvider = context.watch<SettingsProvider>();
 | 
					    SettingsProvider settingsProvider = context.watch<SettingsProvider>();
 | 
				
			||||||
    AppsProvider appsProvider = context.read<AppsProvider>();
 | 
					    AppsProvider appsProvider = context.read<AppsProvider>();
 | 
				
			||||||
 | 
					    LogsProvider logs = context.read<LogsProvider>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (settingsProvider.prefs == null) {
 | 
					    if (settingsProvider.prefs == null) {
 | 
				
			||||||
      settingsProvider.initializeSettings();
 | 
					      settingsProvider.initializeSettings();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      bool isFirstRun = settingsProvider.checkAndFlipFirstRun();
 | 
					      bool isFirstRun = settingsProvider.checkAndFlipFirstRun();
 | 
				
			||||||
      if (isFirstRun) {
 | 
					      if (isFirstRun) {
 | 
				
			||||||
 | 
					        logs.add('This is the first ever run of Obtainium');
 | 
				
			||||||
        // If this is the first run, ask for notification permissions and add Obtainium to the Apps list
 | 
					        // If this is the first run, ask for notification permissions and add Obtainium to the Apps list
 | 
				
			||||||
        Permission.notification.request();
 | 
					        Permission.notification.request();
 | 
				
			||||||
        appsProvider.saveApps([
 | 
					        appsProvider.saveApps([
 | 
				
			||||||
@@ -149,6 +159,10 @@ class _ObtainiumState extends State<Obtainium> {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      // Register the background update task according to the user's setting
 | 
					      // Register the background update task according to the user's setting
 | 
				
			||||||
      if (existingUpdateInterval != settingsProvider.updateInterval) {
 | 
					      if (existingUpdateInterval != settingsProvider.updateInterval) {
 | 
				
			||||||
 | 
					        if (existingUpdateInterval != -1) {
 | 
				
			||||||
 | 
					          logs.add(
 | 
				
			||||||
 | 
					              'Setting update interval to ${settingsProvider.updateInterval}');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        existingUpdateInterval = settingsProvider.updateInterval;
 | 
					        existingUpdateInterval = settingsProvider.updateInterval;
 | 
				
			||||||
        if (existingUpdateInterval == 0) {
 | 
					        if (existingUpdateInterval == 0) {
 | 
				
			||||||
          AndroidAlarmManager.cancel(bgUpdateCheckAlarmId);
 | 
					          AndroidAlarmManager.cancel(bgUpdateCheckAlarmId);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,13 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:obtainium/components/custom_app_bar.dart';
 | 
					import 'package:obtainium/components/custom_app_bar.dart';
 | 
				
			||||||
import 'package:obtainium/components/generated_form.dart';
 | 
					import 'package:obtainium/components/generated_form.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/components/generated_form_modal.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/custom_errors.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/logs_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/settings_provider.dart';
 | 
					import 'package:obtainium/providers/settings_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/source_provider.dart';
 | 
					import 'package:obtainium/providers/source_provider.dart';
 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:provider/provider.dart';
 | 
				
			||||||
 | 
					import 'package:share_plus/share_plus.dart';
 | 
				
			||||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
					import 'package:url_launcher/url_launcher_string.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SettingsPage extends StatefulWidget {
 | 
					class SettingsPage extends StatefulWidget {
 | 
				
			||||||
@@ -238,24 +242,56 @@ class _SettingsPageState extends State<SettingsPage> {
 | 
				
			|||||||
          SliverToBoxAdapter(
 | 
					          SliverToBoxAdapter(
 | 
				
			||||||
            child: Column(
 | 
					            child: Column(
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                height16,
 | 
					                const Divider(
 | 
				
			||||||
                TextButton.icon(
 | 
					                  height: 32,
 | 
				
			||||||
                  style: ButtonStyle(
 | 
					 | 
				
			||||||
                    foregroundColor: MaterialStateProperty.resolveWith<Color>(
 | 
					 | 
				
			||||||
                        (Set<MaterialState> states) {
 | 
					 | 
				
			||||||
                      return Colors.grey;
 | 
					 | 
				
			||||||
                    }),
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                Row(
 | 
				
			||||||
 | 
					                  mainAxisAlignment: MainAxisAlignment.spaceAround,
 | 
				
			||||||
 | 
					                  children: [
 | 
				
			||||||
 | 
					                    TextButton.icon(
 | 
				
			||||||
                      onPressed: () {
 | 
					                      onPressed: () {
 | 
				
			||||||
                        launchUrlString(settingsProvider.sourceUrl,
 | 
					                        launchUrlString(settingsProvider.sourceUrl,
 | 
				
			||||||
                            mode: LaunchMode.externalApplication);
 | 
					                            mode: LaunchMode.externalApplication);
 | 
				
			||||||
                      },
 | 
					                      },
 | 
				
			||||||
                      icon: const Icon(Icons.code),
 | 
					                      icon: const Icon(Icons.code),
 | 
				
			||||||
                  label: Text(
 | 
					                      label: const Text(
 | 
				
			||||||
                    'Source',
 | 
					                        'App Source',
 | 
				
			||||||
                    style: Theme.of(context).textTheme.bodySmall,
 | 
					 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
 | 
					                    TextButton.icon(
 | 
				
			||||||
 | 
					                        onPressed: () {
 | 
				
			||||||
 | 
					                          context.read<LogsProvider>().get().then((logs) {
 | 
				
			||||||
 | 
					                            if (logs.isEmpty) {
 | 
				
			||||||
 | 
					                              showError(ObtainiumError('No Logs'), context);
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                              String logString =
 | 
				
			||||||
 | 
					                                  logs.map((e) => e.toString()).join('\n\n');
 | 
				
			||||||
 | 
					                              showDialog(
 | 
				
			||||||
 | 
					                                  context: context,
 | 
				
			||||||
 | 
					                                  builder: (BuildContext ctx) {
 | 
				
			||||||
 | 
					                                    return GeneratedFormModal(
 | 
				
			||||||
 | 
					                                      title: 'Obtainium App Logs',
 | 
				
			||||||
 | 
					                                      items: const [],
 | 
				
			||||||
 | 
					                                      defaultValues: const [],
 | 
				
			||||||
 | 
					                                      message: logString,
 | 
				
			||||||
 | 
					                                      initValid: true,
 | 
				
			||||||
 | 
					                                    );
 | 
				
			||||||
 | 
					                                  }).then((value) {
 | 
				
			||||||
 | 
					                                if (value != null) {
 | 
				
			||||||
 | 
					                                  Share.share(
 | 
				
			||||||
 | 
					                                      logs
 | 
				
			||||||
 | 
					                                          .map((e) => e.toString())
 | 
				
			||||||
 | 
					                                          .join('\n\n'),
 | 
				
			||||||
 | 
					                                      subject: 'Obtainium App Logs');
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                              });
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                          });
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        icon: const Icon(Icons.bug_report_outlined),
 | 
				
			||||||
 | 
					                        label: const Text('App Logs')),
 | 
				
			||||||
 | 
					                  ],
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
                height16,
 | 
					                height16,
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,8 @@ import 'package:fluttertoast/fluttertoast.dart';
 | 
				
			|||||||
import 'package:install_plugin_v2/install_plugin_v2.dart';
 | 
					import 'package:install_plugin_v2/install_plugin_v2.dart';
 | 
				
			||||||
import 'package:installed_apps/app_info.dart';
 | 
					import 'package:installed_apps/app_info.dart';
 | 
				
			||||||
import 'package:installed_apps/installed_apps.dart';
 | 
					import 'package:installed_apps/installed_apps.dart';
 | 
				
			||||||
import 'package:obtainium/app_sources/github.dart';
 | 
					 | 
				
			||||||
import 'package:obtainium/custom_errors.dart';
 | 
					import 'package:obtainium/custom_errors.dart';
 | 
				
			||||||
 | 
					import 'package:obtainium/providers/logs_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/notifications_provider.dart';
 | 
					import 'package:obtainium/providers/notifications_provider.dart';
 | 
				
			||||||
import 'package:obtainium/providers/settings_provider.dart';
 | 
					import 'package:obtainium/providers/settings_provider.dart';
 | 
				
			||||||
import 'package:package_archive_info/package_archive_info.dart';
 | 
					import 'package:package_archive_info/package_archive_info.dart';
 | 
				
			||||||
@@ -43,6 +43,7 @@ class AppsProvider with ChangeNotifier {
 | 
				
			|||||||
  bool loadingApps = false;
 | 
					  bool loadingApps = false;
 | 
				
			||||||
  bool gettingUpdates = false;
 | 
					  bool gettingUpdates = false;
 | 
				
			||||||
  bool forBGTask = false;
 | 
					  bool forBGTask = false;
 | 
				
			||||||
 | 
					  LogsProvider logs = LogsProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Variables to keep track of the app foreground status (installs can't run in the background)
 | 
					  // Variables to keep track of the app foreground status (installs can't run in the background)
 | 
				
			||||||
  bool isForeground = true;
 | 
					  bool isForeground = true;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										109
									
								
								lib/providers/logs_provider.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								lib/providers/logs_provider.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
 | 
					import 'package:sqflite/sqflite.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const String logTable = 'logs';
 | 
				
			||||||
 | 
					const String idColumn = '_id';
 | 
				
			||||||
 | 
					const String levelColumn = 'level';
 | 
				
			||||||
 | 
					const String messageColumn = 'message';
 | 
				
			||||||
 | 
					const String timestampColumn = 'timestamp';
 | 
				
			||||||
 | 
					const String dbPath = 'logs.db';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LogLevels { debug, info, warning, error }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Log {
 | 
				
			||||||
 | 
					  int? id;
 | 
				
			||||||
 | 
					  late LogLevels level;
 | 
				
			||||||
 | 
					  late String message;
 | 
				
			||||||
 | 
					  DateTime timestamp = DateTime.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, Object?> toMap() {
 | 
				
			||||||
 | 
					    var map = <String, Object?>{
 | 
				
			||||||
 | 
					      idColumn: id,
 | 
				
			||||||
 | 
					      levelColumn: level.index,
 | 
				
			||||||
 | 
					      messageColumn: message,
 | 
				
			||||||
 | 
					      timestampColumn: timestamp.millisecondsSinceEpoch
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Log(this.message, this.level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Log.fromMap(Map<String, Object?> map) {
 | 
				
			||||||
 | 
					    id = map[idColumn] as int;
 | 
				
			||||||
 | 
					    level = LogLevels.values.elementAt(map[levelColumn] as int);
 | 
				
			||||||
 | 
					    message = map[messageColumn] as String;
 | 
				
			||||||
 | 
					    timestamp =
 | 
				
			||||||
 | 
					        DateTime.fromMillisecondsSinceEpoch(map[timestampColumn] as int);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return '${timestamp.toString()}: ${level.name}: $message';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LogsProvider {
 | 
				
			||||||
 | 
					  LogsProvider({bool runDefaultClear = true}) {
 | 
				
			||||||
 | 
					    clear(before: DateTime.now().subtract(const Duration(days: 7)));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Database? db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<Database> getDB() async {
 | 
				
			||||||
 | 
					    db ??= await openDatabase(dbPath, version: 1,
 | 
				
			||||||
 | 
					        onCreate: (Database db, int version) async {
 | 
				
			||||||
 | 
					      await db.execute('''
 | 
				
			||||||
 | 
					create table if not exists $logTable ( 
 | 
				
			||||||
 | 
					  $idColumn integer primary key autoincrement, 
 | 
				
			||||||
 | 
					  $levelColumn integer not null,
 | 
				
			||||||
 | 
					  $messageColumn text not null,
 | 
				
			||||||
 | 
					  $timestampColumn integer not null)
 | 
				
			||||||
 | 
					''');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return db!;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<Log> add(String message, {LogLevels level = LogLevels.info}) async {
 | 
				
			||||||
 | 
					    Log l = Log(message, level);
 | 
				
			||||||
 | 
					    l.id = await (await getDB()).insert(logTable, l.toMap());
 | 
				
			||||||
 | 
					    if (kDebugMode) {
 | 
				
			||||||
 | 
					      print(l);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return l;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<List<Log>> get({DateTime? before, DateTime? after}) async {
 | 
				
			||||||
 | 
					    var where = getWhereDates(before: before, after: after);
 | 
				
			||||||
 | 
					    return (await (await getDB())
 | 
				
			||||||
 | 
					            .query(logTable, where: where.key, whereArgs: where.value))
 | 
				
			||||||
 | 
					        .map((e) => Log.fromMap(e))
 | 
				
			||||||
 | 
					        .toList();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<int> clear({DateTime? before, DateTime? after}) async {
 | 
				
			||||||
 | 
					    var where = getWhereDates(before: before, after: after);
 | 
				
			||||||
 | 
					    var res = await (await getDB())
 | 
				
			||||||
 | 
					        .delete(logTable, where: where.key, whereArgs: where.value);
 | 
				
			||||||
 | 
					    if (res > 0) {
 | 
				
			||||||
 | 
					      add('Cleared $res logs (before = $before, after = $after)');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MapEntry<String?, List<int>?> getWhereDates(
 | 
				
			||||||
 | 
					    {DateTime? before, DateTime? after}) {
 | 
				
			||||||
 | 
					  List<String> where = [];
 | 
				
			||||||
 | 
					  List<int> whereArgs = [];
 | 
				
			||||||
 | 
					  if (before != null) {
 | 
				
			||||||
 | 
					    where.add('$timestampColumn < ?');
 | 
				
			||||||
 | 
					    whereArgs.add(before.millisecondsSinceEpoch);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (after != null) {
 | 
				
			||||||
 | 
					    where.add('$timestampColumn > ?');
 | 
				
			||||||
 | 
					    whereArgs.add(after.millisecondsSinceEpoch);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return whereArgs.isEmpty
 | 
				
			||||||
 | 
					      ? const MapEntry(null, null)
 | 
				
			||||||
 | 
					      : MapEntry(where.join(' and '), whereArgs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								pubspec.lock
									
									
									
									
									
								
							@@ -567,6 +567,20 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dartlang.org"
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.9.0"
 | 
					    version: "1.9.0"
 | 
				
			||||||
 | 
					  sqflite:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqflite
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.2.0+3"
 | 
				
			||||||
 | 
					  sqflite_common:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqflite_common
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.0+2"
 | 
				
			||||||
  stack_trace:
 | 
					  stack_trace:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -588,6 +602,13 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dartlang.org"
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.1.1"
 | 
					    version: "1.1.1"
 | 
				
			||||||
 | 
					  synchronized:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: synchronized
 | 
				
			||||||
 | 
					      url: "https://pub.dartlang.org"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.0.0+3"
 | 
				
			||||||
  term_glyph:
 | 
					  term_glyph:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 | 
				
			|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
					# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
				
			||||||
# In Windows, build-name is used as the major, minor, and patch parts
 | 
					# In Windows, build-name is used as the major, minor, and patch parts
 | 
				
			||||||
# of the product and file versions while build-number is used as the build suffix.
 | 
					# of the product and file versions while build-number is used as the build suffix.
 | 
				
			||||||
version: 0.7.1+57 # When changing this, update the tag in main() accordingly
 | 
					version: 0.7.2+58 # When changing this, update the tag in main() accordingly
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
  sdk: '>=2.18.2 <3.0.0'
 | 
					  sdk: '>=2.18.2 <3.0.0'
 | 
				
			||||||
@@ -56,6 +56,7 @@ dependencies:
 | 
				
			|||||||
  installed_apps: ^1.3.1
 | 
					  installed_apps: ^1.3.1
 | 
				
			||||||
  package_archive_info: ^0.1.0
 | 
					  package_archive_info: ^0.1.0
 | 
				
			||||||
  android_alarm_manager_plus: ^2.1.0
 | 
					  android_alarm_manager_plus: ^2.1.0
 | 
				
			||||||
 | 
					  sqflite: ^2.2.0+3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user