Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4d9287a
feat: implement bugsee data obscure from reported videos
koukibadr Nov 18, 2024
621f58e
feat: customize logs, traces and events reported to Bugsee dashboard
koukibadr Nov 19, 2024
0f12bb3
feat: implement custom attributes and attach file bugsee features
koukibadr Nov 20, 2024
12f2d65
feat: implement global bugsee exception handler
koukibadr Nov 21, 2024
0f27491
chore: add flutter framework rendering error interceptor handler
koukibadr Nov 21, 2024
7f20a67
docs: update project changelog
koukibadr Nov 21, 2024
ac885a0
chore: update bugsee manager singleton registration in main file
koukibadr Nov 22, 2024
f6a6938
chore: add mock attribute to bugsee manager initialization
koukibadr Nov 22, 2024
9906020
chore: add platform check when intializing Bugsee
koukibadr Nov 22, 2024
e7cb678
docs: add Bugsee implementation documentation
koukibadr Nov 28, 2024
934f7f6
chore: update Bugsee integration documentation and event caputring me…
koukibadr Dec 2, 2024
035775e
chore: create global exception interceptor
koukibadr Feb 25, 2025
b545120
Merge branch 'main' into config/bk/integrate-advanced-bugsee
koukibadr Feb 27, 2025
5ac9d49
chore: update code documentation in exception interceptor
koukibadr Feb 27, 2025
b87addb
chore: update production env variables
koukibadr Feb 27, 2025
cced807
chore: update changelog documentation
koukibadr Mar 3, 2025
f8182fc
Merge branch 'main' into config/bk/integrate-advanced-bugsee
koukibadr Mar 4, 2025
99049c3
Merge branch 'main' into config/bk/integrate-advanced-bugsee
carlh98 May 9, 2025
c754cc7
Merge branch 'main' into config/bk/integrate-advanced-bugsee
Sep 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ DAD_JOKES_BASE_URL='https://www.reddit.com/r/dadjokes'
APP_STORE_URL_IOS=https://apps.apple.com/us/app/uno-calculator/id1464736591
APP_STORE_URL_Android=https://play.google.com/store/apps/details?id=uno.platform.calculator
REMOTE_CONFIG_FETCH_INTERVAL_MINUTES=1
DIAGNOSTIC_ENABLED=true
Comment thread
koukibadr marked this conversation as resolved.
DIAGNOSTIC_ENABLED=true
IS_DATA_OBSCURE=true
Comment thread
koukibadr marked this conversation as resolved.
Outdated
Comment thread
koukibadr marked this conversation as resolved.
Outdated
3 changes: 2 additions & 1 deletion src/app/.env.prod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ DAD_JOKES_BASE_URL='https://www.reddit.com/r/dadjokes'
APP_STORE_URL_IOS=https://apps.apple.com/us/app/uno-calculator/id1464736591
APP_STORE_URL_Android=https://play.google.com/store/apps/details?id=uno.platform.calculator
REMOTE_CONFIG_FETCH_INTERVAL_MINUTES=720
DIAGNOSTIC_ENABLED=false
DIAGNOSTIC_ENABLED=false
IS_DATA_OBSCURE=true
6 changes: 5 additions & 1 deletion src/app/.env.staging
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ DAD_JOKES_BASE_URL='https://www.reddit.com/r/dadjokes'
APP_STORE_URL_IOS=https://apps.apple.com/us/app/uno-calculator/id1464736591
APP_STORE_URL_Android=https://play.google.com/store/apps/details?id=uno.platform.calculator
REMOTE_CONFIG_FETCH_INTERVAL_MINUTES=1
DIAGNOSTIC_ENABLED=true
DIAGNOSTIC_ENABLED=true
IS_DATA_OBSCURE=true
DISABLE_LOG_COLLECTION=true
FILTER_LOG_COLLECTION=false
ATTACH_LOG_FILE=true
9 changes: 9 additions & 0 deletions src/app/integration_test/bugsee_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:flutter_test/flutter_test.dart';

/// Test all Bugsee setup features
Future<void> bugseeSetupTest() async {
testWidgets(
'Test Bugsee configuration',
(tester) async {},
Comment thread
koukibadr marked this conversation as resolved.
Outdated
);
}
7 changes: 7 additions & 0 deletions src/app/integration_test/integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:integration_test/integration_test.dart';

import 'bugsee_test.dart';
import 'dad_jokes_page_test.dart';
import 'forced_update_test.dart';
import 'kill_switch_test.dart';
Expand All @@ -12,6 +13,11 @@ import 'kill_switch_test.dart';
Future<void> main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await initializeComponents(isMocked: true);
await registerBugseeManager(
isMock: true,
//A mock hexadecimal-based Bugsee token
bugseeToken: '01234567-0123-0123-0123-0123456789AB',
);

tearDownAll(
() async => await GetIt.I.get<MockingRepository>().setMocking(false),
Expand All @@ -20,4 +26,5 @@ Future<void> main() async {
await dadJokeTest();
await killSwitchTest();
await forcedUpdateTest();
await bugseeSetupTest();
}
53 changes: 50 additions & 3 deletions src/app/lib/access/bugsee/bugsee_configuration_data.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,59 @@
final class BugseeConfigurationData {
import 'package:equatable/equatable.dart';

final class BugseeConfigurationData extends Equatable {
/// 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;

/// Indicate whether bugsee obscure application data in videos and images or not.
Comment thread
koukibadr marked this conversation as resolved.
Outdated
Comment thread
koukibadr marked this conversation as resolved.
Outdated
Comment thread
koukibadr marked this conversation as resolved.
Outdated
final bool? isDataObscured;

/// Indicate whether logs are collected or not.
final bool? isLogCollectionEnabled;

/// Indicate whether logs are filtred during reports or not.
final bool? isLogsFilterEnabled;

/// Indicate whether attaching file in the Bugsee report is enabled or not
final bool? attachLogFileEnabled;

const BugseeConfigurationData({
required this.isBugseeEnabled,
required this.isVideoCaptureEnabled,
this.isBugseeEnabled,
this.isVideoCaptureEnabled,
this.isDataObscured,
this.isLogCollectionEnabled,
this.isLogsFilterEnabled,
this.attachLogFileEnabled,
});

BugseeConfigurationData copyWith({
bool? isBugseeEnabled,
bool? isVideoCaptureEnabled,
bool? isDataObscured,
bool? isLogCollectionEnabled,
bool? isLogsFilterEnabled,
bool? attachLogFileEnabled,
}) =>
BugseeConfigurationData(
isBugseeEnabled: isBugseeEnabled ?? this.isBugseeEnabled,
isVideoCaptureEnabled:
isVideoCaptureEnabled ?? this.isVideoCaptureEnabled,
isDataObscured: isDataObscured ?? this.isDataObscured,
isLogCollectionEnabled:
isLogCollectionEnabled ?? this.isLogCollectionEnabled,
isLogsFilterEnabled: isLogsFilterEnabled ?? this.isLogsFilterEnabled,
attachLogFileEnabled: attachLogFileEnabled ?? this.attachLogFileEnabled,
);

@override
List<Object?> get props => [
isBugseeEnabled,
isVideoCaptureEnabled,
isDataObscured,
isLogCollectionEnabled,
isLogsFilterEnabled,
attachLogFileEnabled,
];
}
87 changes: 87 additions & 0 deletions src/app/lib/access/bugsee/bugsee_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,39 @@ abstract interface class BugseeRepository {

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

/// Update whether data is obscure in shared prefs.
Comment thread
koukibadr marked this conversation as resolved.
Outdated
Future setIsDataObscure(bool isDataObscure);

/// Update the logCollection flag in shared prefs.
Future setIsLogCollectionEnabled(bool isLogCollectionEnabled);

/// Update the logFilter flag in shared prefs.
Future setIsLogFilterEnabled(bool isLogFilterEnabled);

/// Update the attachFile boolean flag in shared prefs.
Future setAttachLogFileEnabled(bool attachLogFile);
}

final class _BugseeRepository implements BugseeRepository {
final String _bugseeEnabledKey = 'bugseeEnabledKey';
final String _videoCaptureKey = 'videoCaptureKey';
final String _dataObscureKey = 'dataObscureKey';
Comment thread
koukibadr marked this conversation as resolved.
Outdated
final String _disableLogCollectionKey = 'disableLogCollectionKey';
final String _disableLogFilterKey = 'disableLogFilterKey';
final String _attachLogFileKey = 'attachLogFileKey';

@override
Future<BugseeConfigurationData> getBugseeConfiguration() async {
final sharedPrefInstance = await SharedPreferences.getInstance();
return BugseeConfigurationData(
isBugseeEnabled: sharedPrefInstance.getBool(_bugseeEnabledKey),
isVideoCaptureEnabled: sharedPrefInstance.getBool(_videoCaptureKey),
isDataObscured: sharedPrefInstance.getBool(_dataObscureKey),
isLogCollectionEnabled:
sharedPrefInstance.getBool(_disableLogCollectionKey),
isLogsFilterEnabled: sharedPrefInstance.getBool(_disableLogFilterKey),
attachLogFileEnabled: sharedPrefInstance.getBool(_attachLogFileKey),
);
}

Expand Down Expand Up @@ -59,4 +80,70 @@ final class _BugseeRepository implements BugseeRepository {
);
}
}

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

bool isSaved = await sharedPrefInstance.setBool(
_dataObscureKey,
isDataObscured,
);

if (!isSaved) {
throw PersistenceException(
message: 'Error while setting $_dataObscureKey $isDataObscured',
);
}
}

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

bool isSaved = await sharedPrefInstance.setBool(
_disableLogCollectionKey,
isLogCollected,
);

if (!isSaved) {
throw PersistenceException(
message:
'Error while setting $_disableLogCollectionKey $isLogCollected',
);
}
}

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

bool isSaved = await sharedPrefInstance.setBool(
_disableLogFilterKey,
isLogFilterEnabled,
);

if (!isSaved) {
throw PersistenceException(
message:
'Error while setting $_disableLogFilterKey $isLogFilterEnabled',
);
}
}

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

bool isSaved = await sharedPrefInstance.setBool(
_attachLogFileKey,
attachLogFile,
);

if (!isSaved) {
throw PersistenceException(
message: 'Error while setting $_attachLogFileKey $attachLogFile',
);
}
}
}
107 changes: 107 additions & 0 deletions src/app/lib/business/bugsee/bugsee_config_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import 'package:equatable/equatable.dart';

enum ConfigErrorEnum {
invalidReleaseMode(error: 'Bugsee is disabled in debug mode'),
invalidToken(error: 'Invalid token, cannot start Bugsee reporting'),
invalidPlatform(error: 'Bugsee cannot be configured on this platform');

final String error;
const ConfigErrorEnum({
required this.error,
});
}

final class BugseeConfigState extends Equatable {
/// Indicate if the app require a restart to reactivate the bugsee configurations
Comment thread
koukibadr marked this conversation as resolved.
Outdated
///
/// `true` only if `isConfigurationValid == true` and bugsee is turned on
final bool isRestartRequired;

/// Indicate if bugsee is enabled or not
/// by default bugsee is enabled if `isConfigurationValid == true`.
final bool isBugseeEnabled;

/// Indicate whether video capturing is enabled or not.
/// enabled by default if `isBugseeEnabled == true`.
///
/// cannot be true if `isBugseeEnabled == false`.
final bool isVideoCaptureEnabled;

/// Indicate if bugsee configuration is valid
Comment thread
koukibadr marked this conversation as resolved.
Outdated
/// config is valid if app in release mode and the provided token is valid
/// following the [bugseeTokenFormat] regex.
final bool isConfigurationValid;

/// Indicate whether data is obscured in report videos
///
/// cannot be true if `isBugseeEnabled == false`.
final bool isDataObscured;

/// Indicate whether log will be collected during Bugsee reporting or not
/// by default logs are collected but filterd.
///
/// This value is initialized from [dotenv.env] and shared prefs storage.
final bool isLogCollectionEnabled;

/// Indicate whether log will be filterd or not
/// by default all logs are filted using [bugseeFilterRegex] defined in [BugseeManager]
///
/// This value is initialized from [dotenv.env] map and shared prefs storage.
final bool isLogFilterEnabled;

/// Indicate whether Bugsee will attach the log file when reporting crashes/exceptions
/// or not
///
/// The initial value is taken from [dotenv.env] and shared prefs.
/// By default it's enabled.
final bool attachLogFile;

/// Indicate the configuration error type (debug, invalid token or invalid platform)
final ConfigErrorEnum? configErrorEnum;

const BugseeConfigState({
this.isRestartRequired = false,
this.isBugseeEnabled = false,
this.isVideoCaptureEnabled = false,
this.isConfigurationValid = false,
this.isDataObscured = false,
this.isLogCollectionEnabled = false,
this.isLogFilterEnabled = false,
this.attachLogFile = false,
this.configErrorEnum,
});

BugseeConfigState copyWith({
bool? isRestartRequired,
bool? isBugseeEnabled,
bool? isVideoCaptureEnabled,
bool? isConfigurationValid,
bool? isDataObscured,
bool? isLogCollectionEnabled,
bool? isLogFilterEnabled,
bool? attachLogFile,
ConfigErrorEnum? configErrorEnum,
}) =>
BugseeConfigState(
isRestartRequired: isRestartRequired ?? this.isRestartRequired,
isBugseeEnabled: isBugseeEnabled ?? this.isBugseeEnabled,
isConfigurationValid: isConfigurationValid ?? this.isConfigurationValid,
isDataObscured: isDataObscured ?? this.isDataObscured,
isLogFilterEnabled: isLogFilterEnabled ?? this.isLogFilterEnabled,
attachLogFile: attachLogFile ?? this.attachLogFile,
isLogCollectionEnabled:
isLogCollectionEnabled ?? this.isLogCollectionEnabled,
isVideoCaptureEnabled:
isVideoCaptureEnabled ?? this.isVideoCaptureEnabled,
configErrorEnum: configErrorEnum ?? this.configErrorEnum,
);

@override
List<Object?> get props => [
isRestartRequired,
isBugseeEnabled,
isVideoCaptureEnabled,
isConfigurationValid,
isDataObscured,
];
}
Loading