Skip to content

Commit

Permalink
feat: add bugsee configuration screen as a new tab in diagnostic page
Browse files Browse the repository at this point in the history
  • Loading branch information
koukibadr committed Nov 14, 2024
1 parent d76958f commit f74f3d3
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 29 deletions.
Binary file removed .DS_Store
Binary file not shown.
4 changes: 1 addition & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@
"program": "src/app/lib/main.dart",
"toolArgs": [
"--dart-define",
"ENV=Production",
"--dart-define",
"BUGSEE_TOKEN=<token>"
"ENV=Production"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion build/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ stages:
firebaseJsonFile: $(InternalFirebaseJson)
firebaseOptionsDartFile: $(InternalFirebaseOptionsDart)
googleServicesJsonFile: $(InternalGoogleServicesJson)
bugseeVariableGroup: 'FlutterApplicationTemplate.BugSee.Tokens'
bugseeVariableGroup: 'FlutterApplicationTemplate.Bugsee.Tokens'

- stage: AppCenter_TestFlight_Staging
condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false'))
Expand Down
2 changes: 1 addition & 1 deletion build/steps-build-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ steps:
projectDirectory: '${{ parameters.pathToSrc }}/app'
verboseMode: true
dartDefine: ENV=$(applicationEnvironment)
dartDefine: BUGSEE_TOKEN=$(AndroidDevToken)
dartDefine: BUGSEE_TOKEN=$(AndroidBugseeToken)

- template: templates/flutter-diagnostics.yml
parameters:
Expand Down
2 changes: 1 addition & 1 deletion build/steps-build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ steps:
verboseMode: true
exportOptionsPlist: '$(exportOptions.secureFilePath)'
dartDefine: ENV=$(applicationEnvironment)
dartDefine: BUGSEE_TOKEN=$(iOSDevToken)
dartDefine: BUGSEE_TOKEN=$(iOSBugseeToken)

- template: templates/flutter-diagnostics.yml
parameters:
Expand Down
Binary file removed src/.DS_Store
Binary file not shown.
12 changes: 12 additions & 0 deletions src/app/lib/access/bugsee/bugsee_configuration_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
final class BugseeConfigurationData {
/// Gets whether the Bugsee SDK is enabled or not. if [Null] it fallbacks to a new installed app so it will be enabled.
final bool? isBugseeEnabled;

/// Indicate whether the video capturing feature in Bugsee is enabled or not.
final bool? isVideoCaptureEnabled;

const BugseeConfigurationData({
required this.isBugseeEnabled,
required this.isVideoCaptureEnabled,
});
}
58 changes: 58 additions & 0 deletions src/app/lib/access/bugsee/bugsee_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:app/access/bugsee/bugsee_configuration_data.dart';
import 'package:app/access/persistence_exception.dart';
import 'package:shared_preferences/shared_preferences.dart';

abstract interface class BugseeRepository {
factory BugseeRepository() = _BugseeRepository;

///Load the current bugsee configuration stored in shared prefs.
Future<BugseeConfigurationData> getBugseeConfiguration();

///Update the current Bugsee enabled flag in shared prefs.
Future setIsBugseeEnabled(bool isBugseeEnabled);

///Update the current video captured or not flag in shared prefs.
Future setIsVideoCaptureEnabled(bool isVideoCaptureEnabled);
}

final class _BugseeRepository implements BugseeRepository {
final String _bugseeEnabledKey = 'bugseeEnabledKey';
final String _videoCaptureKey = 'videoCaptureKey';

@override
Future<BugseeConfigurationData> getBugseeConfiguration() async {
final sharedPrefInstance = await SharedPreferences.getInstance();
return BugseeConfigurationData(
isBugseeEnabled: sharedPrefInstance.getBool(_bugseeEnabledKey),
isVideoCaptureEnabled: sharedPrefInstance.getBool(_videoCaptureKey),
);
}

@override
Future setIsBugseeEnabled(bool isBugseeEnabled) async {
final sharedPrefInstance = await SharedPreferences.getInstance();

bool isSaved = await sharedPrefInstance.setBool(
_bugseeEnabledKey,
isBugseeEnabled,
);

if (!isSaved) {
throw const PersistenceException();
}
}

@override
Future setIsVideoCaptureEnabled(bool isVideoCaptureEnabled) async {
final sharedPrefInstance = await SharedPreferences.getInstance();

bool isSaved = await sharedPrefInstance.setBool(
_videoCaptureKey,
isVideoCaptureEnabled,
);

if (!isSaved) {
throw const PersistenceException();
}
}
}
115 changes: 93 additions & 22 deletions src/app/lib/business/bugsee/bugsee_manager.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'dart:async';
import 'dart:io';

import 'package:app/access/bugsee/bugsee_configuration_data.dart';
import 'package:app/access/bugsee/bugsee_repository.dart';
import 'package:bugsee_flutter/bugsee_flutter.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
Expand All @@ -12,8 +15,15 @@ const String bugseeTokenFormat =
abstract interface class BugseeManager {
factory BugseeManager({
required Logger logger,
required BugseeRepository bugseeRepository,
}) = _BugseeManager;

bool get configurationHasChanged;

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
Expand All @@ -27,48 +37,80 @@ abstract interface class BugseeManager {
required Exception exception,
StackTrace? stackTrace,
});

///Manually update the current BugseeEnabled flag in shared prefs and in current manager singleton.
Future<void> updateBugseeEnabledValue(bool isBugseeEnabled);

///Manually update the current enableVideoCapture flag in shared prefs and in current manager singleton.
Future<void> updateIsVideoCuptureValue(bool isBugseeEnabled);

///Manually shows the built-in capture log report screen of Bugsee.
Future<void> showCaptureLogReport();
}

final class _BugseeManager implements BugseeManager {
final Logger logger;

late BugseeLaunchOptions launchOptions;

late bool _isBugSeeInitialized;
final BugseeRepository bugseeRepository;

_BugseeManager({
required this.logger,
required this.bugseeRepository,
});

@override
bool configurationHasChanged = false;

@override
bool bugseeIsEnabled = false;

@override
late bool captureVideoIsEnabled = false;

@override
bool isValidConfiguration = true;

late bool _isBugSeeInitialized;
late BugseeLaunchOptions launchOptions;

@override
Future<void> initialize({
String? bugseeToken,
}) async {
BugseeConfigurationData bugseeConfigurationData =
await bugseeRepository.getBugseeConfiguration();

initializeLaunchOptions();
_isBugSeeInitialized = false;
if (kDebugMode) {
logger.i("BUGSEE: deactivated in debug mode");
return;
}

if (bugseeToken == null ||
!RegExp(bugseeTokenFormat).hasMatch(bugseeToken)) {
logger.i("BUGSEE: token is null or invalid, bugsee won't be initialized");
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");
}
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,
);
}

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,
);
bugseeIsEnabled = _isBugSeeInitialized;
captureVideoIsEnabled = _isBugSeeInitialized;
}

Future initializeLaunchOptions() async {
Expand All @@ -84,8 +126,37 @@ final class _BugseeManager implements BugseeManager {
required Exception exception,
StackTrace? stackTrace,
}) async {
if (_isBugSeeInitialized) {
if (bugseeIsEnabled) {
await Bugsee.logException(exception, stackTrace);
}
}

@override
Future<void> updateBugseeEnabledValue(bool isBugseeEnabled) async {
if (isValidConfiguration) {
await bugseeRepository.setIsBugseeEnabled(isBugseeEnabled);
bugseeIsEnabled = isBugseeEnabled;
configurationHasChanged = bugseeIsEnabled != _isBugSeeInitialized;
captureVideoIsEnabled = bugseeIsEnabled;
}
}

@override
Future<void> updateIsVideoCuptureValue(bool isVideoCaptureEnabled) async {
if (bugseeIsEnabled) {
captureVideoIsEnabled = isVideoCaptureEnabled;
if (!isVideoCaptureEnabled) {
await Bugsee.pause();
} else {
await Bugsee.resume();
}
}
}

@override
Future<void> showCaptureLogReport() async {
if (bugseeIsEnabled) {
await Bugsee.showReportDialog();
}
}
}
3 changes: 3 additions & 0 deletions src/app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';

import 'package:alice/alice.dart';
import 'package:app/access/bugsee/bugsee_repository.dart';
import 'package:app/access/dad_jokes/dad_jokes_mocked_repository.dart';
import 'package:app/access/dad_jokes/dad_jokes_repository.dart';
import 'package:app/access/dad_jokes/favorite_dad_jokes_mocked_repository.dart';
Expand Down Expand Up @@ -119,9 +120,11 @@ Future _registerAndLoadLoggers() async {
}

Future _registerBugseeManager() async {
GetIt.I.registerSingleton<BugseeRepository>(BugseeRepository());
GetIt.I.registerSingleton<BugseeManager>(
BugseeManager(
logger: GetIt.I.get<Logger>(),
bugseeRepository: GetIt.I.get<BugseeRepository>(),
),
);
GetIt.I.get<BugseeManager>().initialize(
Expand Down
Loading

0 comments on commit f74f3d3

Please sign in to comment.