diff --git a/src/app/android/settings.gradle b/src/app/android/settings.gradle index 08944374..ddbef7fe 100644 --- a/src/app/android/settings.gradle +++ b/src/app/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version '7.4.2' apply false + id "com.android.application" version '7.3.0' apply false // START: FlutterFire Configuration id "com.google.gms.google-services" version "4.3.15" apply false // END: FlutterFire Configuration diff --git a/src/app/lib/access/bugsee/bugsee_repository.dart b/src/app/lib/access/bugsee/bugsee_repository.dart index 5fbf3448..3f270eb3 100644 --- a/src/app/lib/access/bugsee/bugsee_repository.dart +++ b/src/app/lib/access/bugsee/bugsee_repository.dart @@ -5,13 +5,13 @@ import 'package:shared_preferences/shared_preferences.dart'; abstract interface class BugseeRepository { factory BugseeRepository() = _BugseeRepository; - ///Load the current bugsee configuration stored in shared prefs. + /// Load the current bugsee configuration stored in shared prefs. Future getBugseeConfiguration(); - ///Update the current Bugsee enabled flag in shared prefs. + /// Update the current Bugsee enabled flag in shared prefs. Future setIsBugseeEnabled(bool isBugseeEnabled); - ///Update the current video captured or not flag in shared prefs. + /// Update the current video captured or not flag in shared prefs. Future setIsVideoCaptureEnabled(bool isVideoCaptureEnabled); } @@ -38,7 +38,9 @@ final class _BugseeRepository implements BugseeRepository { ); if (!isSaved) { - throw const PersistenceException(); + throw PersistenceException( + message: 'Error while setting $_bugseeEnabledKey $isBugseeEnabled', + ); } } @@ -52,7 +54,9 @@ final class _BugseeRepository implements BugseeRepository { ); if (!isSaved) { - throw const PersistenceException(); + throw PersistenceException( + message: 'Error while setting $_videoCaptureKey $isVideoCaptureEnabled', + ); } } } diff --git a/src/app/lib/access/persistence_exception.dart b/src/app/lib/access/persistence_exception.dart index 669ec4fb..f1d76709 100644 --- a/src/app/lib/access/persistence_exception.dart +++ b/src/app/lib/access/persistence_exception.dart @@ -1,5 +1,8 @@ /// Exception thrown when something couldn't be persisted in the shared preference. /// It was created due to https://github.com/flutter/flutter/issues/146070. final class PersistenceException implements Exception { - const PersistenceException(); + /// A descriptive message detailing the persistence exception + final String? message; + + const PersistenceException({this.message}); } diff --git a/src/app/lib/business/bugsee/bugsee_manager.dart b/src/app/lib/business/bugsee/bugsee_manager.dart index ac0177e5..c7c89741 100644 --- a/src/app/lib/business/bugsee/bugsee_manager.dart +++ b/src/app/lib/business/bugsee/bugsee_manager.dart @@ -18,33 +18,41 @@ abstract interface class BugseeManager { required BugseeRepository bugseeRepository, }) = _BugseeManager; - bool get configurationHasChanged; + bool get isRequireRestart; bool get bugseeIsEnabled; bool get captureVideoIsEnabled; bool get isValidConfiguration; - ///initialize bugsee with given token - ///bugsee is not available in debug mode - ///* [bugseeToken]: nullable bugsee token, if null bugsee won't be initialized make sure you provide - ///[BUGSEE_TOKEN] in the env using `--dart-define` or `launch.json` on vscode + /// initialize bugsee with given token + /// bugsee is not available in debug mode + /// * [bugseeToken]: nullable bugsee token, if null bugsee won't be initialized make sure you provide + /// [BUGSEE_TOKEN] in the env using `--dart-define` or `launch.json` on vscode Future initialize({ String? bugseeToken, }); - ///Manually log a provided exception with a stack trace + /// Manually log a provided exception with a stack trace + /// (medium severity exception in Bugsee dashboard) Future logException({ required Exception exception, StackTrace? stackTrace, }); - ///Manually update the current BugseeEnabled flag in shared prefs and in current manager singleton. - Future updateBugseeEnabledValue(bool isBugseeEnabled); + /// Manually log an unhandled exception with a stack trace + /// (critical severity exception in Bugsee dashboard) + Future logUnhandledException({ + required Exception exception, + StackTrace? stackTrace, + }); + + /// Manually update the current BugseeEnabled flag in shared prefs and in current manager singleton. + Future setIsBugseeEnabled(bool isBugseeEnabled); - ///Manually update the current enableVideoCapture flag in shared prefs and in current manager singleton. - Future updateIsVideoCuptureValue(bool isBugseeEnabled); + /// Manually update the current enableVideoCapture flag in shared prefs and in current manager singleton. + Future setIsVideoCaptureEnabled(bool isBugseeEnabled); - ///Manually shows the built-in capture log report screen of Bugsee. + /// Manually shows the built-in capture log report screen of Bugsee. Future showCaptureLogReport(); } @@ -58,7 +66,7 @@ final class _BugseeManager implements BugseeManager { }); @override - bool configurationHasChanged = false; + bool isRequireRestart = false; @override bool bugseeIsEnabled = false; @@ -70,7 +78,7 @@ final class _BugseeManager implements BugseeManager { bool isValidConfiguration = true; late bool _isBugSeeInitialized; - late BugseeLaunchOptions launchOptions; + BugseeLaunchOptions? launchOptions; @override Future initialize({ @@ -79,35 +87,26 @@ final class _BugseeManager implements BugseeManager { BugseeConfigurationData bugseeConfigurationData = await bugseeRepository.getBugseeConfiguration(); - initializeLaunchOptions(); + launchOptions = initializeLaunchOptions(); _isBugSeeInitialized = false; - if (kDebugMode || - bugseeToken == null || - !RegExp(bugseeTokenFormat).hasMatch(bugseeToken)) { + if (kDebugMode) { isValidConfiguration = false; - if (!kDebugMode) { - logger.i( - "BUGSEE: token is null or invalid, bugsee won't be initialized", - ); - } else { - logger.i("BUGSEE: deactivated in debug mode"); - } + logger.i("BUGSEE: deactivated in debug mode"); return; - } else if (bugseeConfigurationData.isBugseeEnabled ?? true) { - HttpOverrides.global = Bugsee.defaultHttpOverrides; - await Bugsee.launch( - bugseeToken, - appRunCallback: (isBugseeLaunched) { - if (!isBugseeLaunched) { - logger.e( - "BUGSEE: not initialized, verify bugsee token configuration", - ); - } - _isBugSeeInitialized = isBugseeLaunched; - }, - launchOptions: launchOptions, + } + + if (bugseeToken == null || + !RegExp(bugseeTokenFormat).hasMatch(bugseeToken)) { + isValidConfiguration = false; + logger.i( + "BUGSEE: token is null or invalid, bugsee won't be initialized", ); + return; + } + + if (bugseeConfigurationData.isBugseeEnabled ?? true) { + await launchBugseeLogger(bugseeToken); } bugseeIsEnabled = _isBugSeeInitialized; @@ -115,12 +114,29 @@ final class _BugseeManager implements BugseeManager { (bugseeConfigurationData.isVideoCaptureEnabled ?? true); } - Future initializeLaunchOptions() async { + Future launchBugseeLogger(String bugseeToken) async { + HttpOverrides.global = Bugsee.defaultHttpOverrides; + await Bugsee.launch( + bugseeToken, + appRunCallback: (isBugseeLaunched) { + if (!isBugseeLaunched) { + logger.e( + "BUGSEE: not initialized, verify bugsee token configuration", + ); + } + _isBugSeeInitialized = isBugseeLaunched; + }, + launchOptions: launchOptions, + ); + } + + BugseeLaunchOptions? initializeLaunchOptions() { if (Platform.isAndroid) { - launchOptions = AndroidLaunchOptions(); + return AndroidLaunchOptions(); } else if (Platform.isIOS) { - launchOptions = IOSLaunchOptions(); + return IOSLaunchOptions(); } + return null; } @override @@ -134,17 +150,32 @@ final class _BugseeManager implements BugseeManager { } @override - Future updateBugseeEnabledValue(bool isBugseeEnabled) async { + Future logUnhandledException({ + required Exception exception, + StackTrace? stackTrace, + }) async { + if (bugseeIsEnabled) { + await Bugsee.logUnhandledException(exception); + } + } + + @override + Future setIsBugseeEnabled(bool isBugseeEnabled) async { if (isValidConfiguration) { await bugseeRepository.setIsBugseeEnabled(isBugseeEnabled); + + isRequireRestart = _isBugSeeInitialized && isBugseeEnabled; bugseeIsEnabled = isBugseeEnabled; - configurationHasChanged = bugseeIsEnabled != _isBugSeeInitialized; captureVideoIsEnabled = bugseeIsEnabled; + + if (!isRequireRestart) { + await Bugsee.stop(); + } } } @override - Future updateIsVideoCuptureValue(bool isVideoCaptureEnabled) async { + Future setIsVideoCaptureEnabled(bool isVideoCaptureEnabled) async { if (bugseeIsEnabled) { captureVideoIsEnabled = isVideoCaptureEnabled; await bugseeRepository.setIsVideoCaptureEnabled(isVideoCaptureEnabled); diff --git a/src/app/lib/presentation/diagnostic/bugsee_configuration_widget.dart b/src/app/lib/presentation/diagnostic/bugsee_configuration_widget.dart index 613c5eab..5f53fc4d 100644 --- a/src/app/lib/presentation/diagnostic/bugsee_configuration_widget.dart +++ b/src/app/lib/presentation/diagnostic/bugsee_configuration_widget.dart @@ -25,7 +25,7 @@ class _BugseeConfigurationWidgetState extends State { super.initState(); isConfigEnabled = bugseeManager.bugseeIsEnabled; isCaptureVideoEnabled = bugseeManager.captureVideoIsEnabled; - requireRestart = bugseeManager.configurationHasChanged; + requireRestart = bugseeManager.isRequireRestart; } @override @@ -53,7 +53,7 @@ class _BugseeConfigurationWidgetState extends State { Container( color: const Color.fromARGB(170, 255, 0, 0), child: const Text( - "Bugsee config has changed please restart the app.", + "In order to reactivate Bugsee logger restart the app.", style: TextStyle( color: Colors.white, fontSize: 20, @@ -66,11 +66,11 @@ class _BugseeConfigurationWidgetState extends State { label: 'Bugsee enabled', value: isConfigEnabled, onChanged: (value) async { - bugseeManager.updateBugseeEnabledValue(value); + await bugseeManager.setIsBugseeEnabled(value); setState(() { isConfigEnabled = bugseeManager.bugseeIsEnabled; isCaptureVideoEnabled = bugseeManager.captureVideoIsEnabled; - requireRestart = bugseeManager.configurationHasChanged; + requireRestart = bugseeManager.isRequireRestart; }); }, ), @@ -78,7 +78,7 @@ class _BugseeConfigurationWidgetState extends State { label: 'Video capture enabled', value: isCaptureVideoEnabled, onChanged: (value) async { - bugseeManager.updateIsVideoCuptureValue(value); + await bugseeManager.setIsVideoCaptureEnabled(value); setState(() { isCaptureVideoEnabled = bugseeManager.captureVideoIsEnabled; }); @@ -92,6 +92,12 @@ class _BugseeConfigurationWidgetState extends State { bugseeManager.logException(exception: Exception()); }, ), + DiagnosticButton( + label: 'Log an unhandled exception', + onPressed: () { + bugseeManager.logUnhandledException(exception: Exception()); + }, + ), DiagnosticButton( label: 'Show report dialog', onPressed: () {