From 676335a2ef14c7b7ad6494011cfc84c731b98454 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:25:44 +0100 Subject: [PATCH 01/11] refactor: logger, improve env, init app process --- ...nversation_message_actions_provider.c.dart | 2 +- ...rsation_message_management_provider.c.dart | 2 +- .../config/providers/config_provider.c.dart | 2 +- .../providers/force_update_provider.c.dart | 2 - .../force_update_util_provider.c.dart | 2 +- .../features/core/model/feature_flags.dart | 9 ++ .../core/providers/dio_provider.c.dart | 9 +- .../core/providers/env_provider.c.dart | 37 +++----- .../providers/feature_flags_provider.c.dart | 33 +++++-- .../core/providers/init_provider.c.dart | 18 ++-- .../core/views/pages/error_modal.dart | 3 +- lib/app/features/debug/views/debug_page.dart | 86 +++++++++++++++++++ .../router/main_tabs/main_tab_navigation.dart | 11 +++ .../providers/go_router_provider.c.dart | 5 +- .../ion_identity/ion_identity_logger.dart | 20 +++++ .../ion_identity/ion_identity_provider.c.dart | 23 +++-- lib/app/services/logger/config.dart | 15 ---- lib/app/services/logger/logger.dart | 39 +++++++++ .../media_service/banuba_service.c.dart | 2 +- lib/app/services/nostr/nostr.dart | 13 ++- lib/app/services/nostr/nostr_logger.dart | 34 ++++++++ .../riverpod/root_provider_scope.dart | 9 +- lib/main.dart | 12 +-- .../ion_identity_client/example/pubspec.lock | 8 -- .../network_service_locator.dart | 16 ++-- .../lib/src/ion_identity_config.dart | 11 ++- packages/ion_identity_client/pubspec.yaml | 1 - pubspec.lock | 28 +++--- pubspec.yaml | 3 +- test/user/follow_list_test.dart | 2 +- test/user/interests_set_test.dart | 2 +- test/user/interests_test.dart | 2 +- test/user/user_delegation_test.dart | 2 +- 33 files changed, 331 insertions(+), 132 deletions(-) create mode 100644 lib/app/features/debug/views/debug_page.dart create mode 100644 lib/app/services/ion_identity/ion_identity_logger.dart delete mode 100644 lib/app/services/logger/config.dart create mode 100644 lib/app/services/nostr/nostr_logger.dart diff --git a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart index f4062f696..2577de1fb 100644 --- a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart @@ -37,7 +37,7 @@ Future> conversationMessageActionsService return ConversationMessageActionsService( eventSigner: eventSigner, databaseService: databaseService, - env: ref.watch(envProvider.notifier), + env: ref.read(envProvider.notifier), userPubkey: await ref.watch(currentPubkeySelectorProvider.future), sealService: ref.watch(ionConnectSealServiceProvider), nostrNotifier: ref.watch(nostrNotifierProvider.notifier), diff --git a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart index 006a09673..67c290f34 100644 --- a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart @@ -36,7 +36,7 @@ Future> conversationMessageManagementS return ConversationMessageManagementService( eventSigner: eventSigner, - env: ref.watch(envProvider.notifier), + env: ref.read(envProvider.notifier), fileCacheService: ref.watch(fileCacheServiceProvider), sealService: ref.watch(ionConnectSealServiceProvider), compressionService: ref.watch(compressServiceProvider), diff --git a/lib/app/features/config/providers/config_provider.c.dart b/lib/app/features/config/providers/config_provider.c.dart index 6c9d613d5..6a960bb88 100644 --- a/lib/app/features/config/providers/config_provider.c.dart +++ b/lib/app/features/config/providers/config_provider.c.dart @@ -47,7 +47,7 @@ Future configForPlatform(Ref ref) async { } } - final baseUrl = ref.watch(envProvider.notifier).get(EnvVariable.ION_ORIGIN); + final baseUrl = ref.read(envProvider.notifier).get(EnvVariable.ION_ORIGIN); final configName = getPlatformConfigName(); final path = '$baseUrl/v1/config/$configName'; diff --git a/lib/app/features/config/providers/force_update_provider.c.dart b/lib/app/features/config/providers/force_update_provider.c.dart index ee476bcbf..541b4a71d 100644 --- a/lib/app/features/config/providers/force_update_provider.c.dart +++ b/lib/app/features/config/providers/force_update_provider.c.dart @@ -42,8 +42,6 @@ class ForceUpdate extends _$ForceUpdate { } Future _checkAndUpdateConfig() async { - await ref.read(envProvider.future); - final refetchIntervalInMilliseconds = ref.read(envProvider.notifier).get(EnvVariable.VERSIONS_CONFIG_REFETCH_INTERVAL); diff --git a/lib/app/features/config/providers/force_update_util_provider.c.dart b/lib/app/features/config/providers/force_update_util_provider.c.dart index db44e01b9..d55743f2b 100644 --- a/lib/app/features/config/providers/force_update_util_provider.c.dart +++ b/lib/app/features/config/providers/force_update_util_provider.c.dart @@ -56,5 +56,5 @@ class ForceUpdateUtil { @riverpod ForceUpdateUtil forceUpdateService(Ref ref) { - return ForceUpdateUtil(ref.watch(envProvider.notifier)); + return ForceUpdateUtil(ref.read(envProvider.notifier)); } diff --git a/lib/app/features/core/model/feature_flags.dart b/lib/app/features/core/model/feature_flags.dart index a0cef6dff..1aedfe66d 100644 --- a/lib/app/features/core/model/feature_flags.dart +++ b/lib/app/features/core/model/feature_flags.dart @@ -19,6 +19,15 @@ final class FeedFeatureFlag extends FeatureFlag { static const showMentionsSuggestions = FeedFeatureFlag._(key: 'showMentionsSuggestions'); } +final class LoggerFeatureFlag extends FeatureFlag { + const LoggerFeatureFlag._({required super.key}); + + static const logApp = FeedFeatureFlag._(key: 'logApp'); + static const logRouters = FeedFeatureFlag._(key: 'logRouters'); + static const logNostrDart = FeedFeatureFlag._(key: 'logNostrDart'); + static const logIonIdentityClient = FeedFeatureFlag._(key: 'logIonIdentityClient'); +} + /// /// TODO: remove this once before production release /// It hides creators without picture from the discover creators page diff --git a/lib/app/features/core/providers/dio_provider.c.dart b/lib/app/features/core/providers/dio_provider.c.dart index 215bdb187..01548d628 100644 --- a/lib/app/features/core/providers/dio_provider.c.dart +++ b/lib/app/features/core/providers/dio_provider.c.dart @@ -2,7 +2,8 @@ import 'package:dio/dio.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:ion/app/services/logger/config.dart'; +import 'package:ion/app/features/core/model/feature_flags.dart'; +import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -10,9 +11,13 @@ part 'dio_provider.c.g.dart'; @riverpod Dio dio(Ref ref) { + final logApp = ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logApp); + final dio = Dio(); - if (LoggerConfig.dioLogsEnabled) { + + if (logApp) { dio.interceptors.add(PrettyDioLogger()); } + return dio; } diff --git a/lib/app/features/core/providers/env_provider.c.dart b/lib/app/features/core/providers/env_provider.c.dart index f29249bbf..e086d15f8 100644 --- a/lib/app/features/core/providers/env_provider.c.dart +++ b/lib/app/features/core/providers/env_provider.c.dart @@ -3,7 +3,6 @@ // ignore_for_file: constant_identifier_names import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:ion/generated/assets.gen.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'env_provider.c.g.dart'; @@ -21,35 +20,19 @@ enum EnvVariable { @Riverpod(keepAlive: true) class Env extends _$Env { @override - Future build() async { - await dotenv.load(fileName: Assets.aApp); - final notDefined = _getNotDefined(); - if (notDefined.isNotEmpty) { - throw Exception('Invalid ENV value for $notDefined'); - } - } - - List _getNotDefined() { - return EnvVariable.values - .where((EnvVariable element) => dotenv.maybeGet(element.name) == null) - .toList(); - } + void build() {} + /// Gets a typed environment variable value. + /// Throws if the variable is not found or cannot be converted to type [T]. T get(EnvVariable variable) { final value = dotenv.get(variable.name); - if (T == bool) { - return (value.toLowerCase() == 'true') as T; - } - - if (T == int) { - return int.parse(value) as T; - } - - if (T == double) { - return double.parse(value) as T; - } - - return value as T; + return switch (T) { + bool => (value.toLowerCase() == 'true') as T, + int => int.parse(value) as T, + double => double.parse(value) as T, + String => value as T, + _ => throw Exception('Unsupported type $T'), + }; } } diff --git a/lib/app/features/core/providers/feature_flags_provider.c.dart b/lib/app/features/core/providers/feature_flags_provider.c.dart index 6a61d9cd7..2f8e247ae 100644 --- a/lib/app/features/core/providers/feature_flags_provider.c.dart +++ b/lib/app/features/core/providers/feature_flags_provider.c.dart @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 import 'package:ion/app/features/core/model/feature_flags.dart'; +import 'package:ion/app/features/core/providers/env_provider.c.dart'; import 'package:ion/app/services/logger/logger.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -35,19 +36,41 @@ final class LocalFeatureFlagsService extends FeatureFlagsService { Set get supportedFlags => _featuresMap.keys.toSet(); } +final class LoggerFeatureFlagsService extends FeatureFlagsService { + factory LoggerFeatureFlagsService() { + return const LoggerFeatureFlagsService._({ + LoggerFeatureFlag.logApp: true, + LoggerFeatureFlag.logRouters: false, + LoggerFeatureFlag.logNostrDart: true, + LoggerFeatureFlag.logIonIdentityClient: true, + }); + } + + const LoggerFeatureFlagsService._(this._featuresMap); + + final Map _featuresMap; + + @override + bool? get(FeatureFlag flag) => _featuresMap[flag]; + + @override + Set get supportedFlags => _featuresMap.keys.toSet(); +} + @Riverpod(keepAlive: true) class FeatureFlags extends _$FeatureFlags { - late final Set _services; - @override - Future build() async { - _services = { + Set build() { + final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); + + return { LocalFeatureFlagsService(), + if (showDebugInfo) LoggerFeatureFlagsService(), }; } bool get(FeatureFlag flag, {bool defaultValue = false}) { - for (final service in _services) { + for (final service in state) { if (service.supportedFlags.contains(flag)) { final value = service.get(flag); diff --git a/lib/app/features/core/providers/init_provider.c.dart b/lib/app/features/core/providers/init_provider.c.dart index 3b3eaa256..a5c97425f 100644 --- a/lib/app/features/core/providers/init_provider.c.dart +++ b/lib/app/features/core/providers/init_provider.c.dart @@ -3,33 +3,35 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/auth/providers/auth_provider.c.dart'; import 'package:ion/app/features/auth/providers/onboarding_complete_provider.c.dart'; +import 'package:ion/app/features/core/model/feature_flags.dart'; import 'package:ion/app/features/core/permissions/providers/permissions_provider.c.dart'; -import 'package:ion/app/features/core/providers/env_provider.c.dart'; +import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/features/core/providers/template_provider.c.dart'; import 'package:ion/app/features/core/providers/window_manager_provider.c.dart'; import 'package:ion/app/features/wallet/data/coins/domain/coin_initializer.c.dart'; import 'package:ion/app/services/nostr/nostr.dart'; +import 'package:ion/app/services/nostr/nostr_logger.dart'; import 'package:ion/app/services/storage/local_storage.c.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'init_provider.c.g.dart'; @Riverpod(keepAlive: true) Future initApp(Ref ref) async { - Nostr.initialize(); + final logNostrDart = ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logNostrDart); + + Nostr.initialize( + logNostrDart ? '${(await getTemporaryDirectory()).path}/${NostrLogger.logFileName}' : null, + ); await Future.wait([ ref.read(windowManagerProvider.notifier).show(), - ref.read(envProvider.future), ref.read(sharedPreferencesProvider.future), - ]); - - await Future.wait([ ref.read(appTemplateProvider.future), ref.read(authProvider.future), ref.read(permissionsProvider.notifier).checkAllPermissions(), ref.read(coinInitializerProvider).initialize(), + ref.read(onboardingCompleteProvider.future), ]); - - await ref.read(onboardingCompleteProvider.future); } diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index c398a5cbf..f1de67f69 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -19,7 +19,8 @@ class ErrorModal extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final showDebugInfo = ref.watch(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); + final showDebugInfo = + ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO) ?? false; final errorInfo = switch (error) { Object _ when showDebugInfo => error.toString(), diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart new file mode 100644 index 000000000..857b23095 --- /dev/null +++ b/lib/app/features/debug/views/debug_page.dart @@ -0,0 +1,86 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart'; +import 'package:ion/app/services/ion_identity/ion_identity_logger.dart'; +import 'package:ion/app/services/logger/logger.dart'; +import 'package:ion/app/services/nostr/nostr_logger.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:share_plus/share_plus.dart'; + +class DebugPage extends ConsumerWidget { + const DebugPage({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Scaffold( + appBar: NavigationAppBar.screen( + title: const Text('🐞 Debug'), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: ListView( + children: [ + ExpansionTile( + title: const Text('Logs'), + children: [ + ListTile( + title: const Text('App logs'), + onTap: () async { + final tempDir = await getTemporaryDirectory(); + final file = File('${tempDir.path}/${Logger.logFileName}'); + + if (file.existsSync()) { + await Share.shareXFiles([XFile(file.path)]); + } else if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('No logs found'), + ), + ); + } + }, + ), + ListTile( + title: const Text('ION Identity Client'), + onTap: () async { + final tempDir = await getTemporaryDirectory(); + final file = File('${tempDir.path}/${IonIdentityLogger.logFileName}'); + + if (file.existsSync()) { + await Share.shareXFiles([XFile(file.path)]); + } else if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('No logs found'), + ), + ); + } + }, + ), + ListTile( + title: const Text('Nostr'), + onTap: () async { + final tempDir = await getTemporaryDirectory(); + final file = File('${tempDir.path}/${NostrLogger.logFileName}'); + + if (file.existsSync()) { + await Share.shareXFiles([XFile(file.path)]); + } else if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('No logs found'), + ), + ); + } + }, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/app/router/main_tabs/main_tab_navigation.dart b/lib/app/router/main_tabs/main_tab_navigation.dart index b8fdca71c..a1a14a9dc 100644 --- a/lib/app/router/main_tabs/main_tab_navigation.dart +++ b/lib/app/router/main_tabs/main_tab_navigation.dart @@ -9,6 +9,8 @@ import 'package:ion/app/extensions/extensions.dart'; import 'package:ion/app/features/chat/providers/user_chat_relays_provider.c.dart'; import 'package:ion/app/features/chat/recent_chats/providers/conversations_edit_mode_provider.c.dart'; import 'package:ion/app/features/chat/recent_chats/views/components/conversation_edit_bottom_bar/conversation_edit_bottom_bar.dart'; +import 'package:ion/app/features/core/providers/env_provider.c.dart'; +import 'package:ion/app/features/debug/views/debug_page.dart'; import 'package:ion/app/hooks/use_on_init.dart'; import 'package:ion/app/router/main_tabs/components/components.dart'; @@ -106,6 +108,15 @@ class _BottomNavBarContent extends ConsumerWidget { child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () => onTabPressed(tabItem), + onLongPress: + ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO) && + tabItem == TabItem.profile + ? () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const DebugPage(), + ), + ) + : null, child: Container( padding: EdgeInsets.symmetric(vertical: 9.0.s), color: context.theme.appColors.secondaryBackground, diff --git a/lib/app/router/providers/go_router_provider.c.dart b/lib/app/router/providers/go_router_provider.c.dart index c2f4286da..3ed056078 100644 --- a/lib/app/router/providers/go_router_provider.c.dart +++ b/lib/app/router/providers/go_router_provider.c.dart @@ -6,15 +6,16 @@ import 'package:ion/app/extensions/extensions.dart'; import 'package:ion/app/features/auth/providers/auth_provider.c.dart'; import 'package:ion/app/features/auth/providers/onboarding_complete_provider.c.dart'; import 'package:ion/app/features/auth/views/pages/link_new_device/link_new_device_dialog.dart'; +import 'package:ion/app/features/core/model/feature_flags.dart'; import 'package:ion/app/features/core/permissions/data/models/permissions_types.dart'; import 'package:ion/app/features/core/permissions/providers/permissions_provider.c.dart'; +import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/features/core/providers/init_provider.c.dart'; import 'package:ion/app/features/core/providers/splash_provider.c.dart'; import 'package:ion/app/features/core/views/pages/error_page.dart'; import 'package:ion/app/features/user/providers/user_metadata_provider.c.dart'; import 'package:ion/app/router/app_router_listenable.dart'; import 'package:ion/app/router/app_routes.c.dart'; -import 'package:ion/app/services/logger/config.dart'; import 'package:ion/app/services/logger/logger.dart'; import 'package:ion/app/services/ui_event_queue/ui_event_queue_notifier.c.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -49,7 +50,7 @@ GoRouter goRouter(Ref ref) { routes: $appRoutes, errorBuilder: (context, state) => ErrorPage(error: state.error ?? Exception('Unknown error')), initialLocation: SplashRoute().location, - debugLogDiagnostics: LoggerConfig.routerLogsEnabled, + debugLogDiagnostics: ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logRouters), navigatorKey: rootNavigatorKey, ); } diff --git a/lib/app/services/ion_identity/ion_identity_logger.dart b/lib/app/services/ion_identity/ion_identity_logger.dart new file mode 100644 index 000000000..34d892ab9 --- /dev/null +++ b/lib/app/services/ion_identity/ion_identity_logger.dart @@ -0,0 +1,20 @@ +import 'dart:developer' as developer; +import 'dart:io'; + +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; + +class IonIdentityLogger extends PrettyDioLogger { + IonIdentityLogger({File? fileOutput}) + : super( + requestBody: true, + requestHeader: true, + logPrint: fileOutput != null + ? (message) { + fileOutput.writeAsStringSync('$message\n', mode: FileMode.append); + developer.log(message.toString()); + } + : (Object message) => developer.log(message.toString()), + ); + + static const logFileName = 'ion_identity_client_logs.txt'; +} diff --git a/lib/app/services/ion_identity/ion_identity_provider.c.dart b/lib/app/services/ion_identity/ion_identity_provider.c.dart index 9f0e4f53d..d86606814 100644 --- a/lib/app/services/ion_identity/ion_identity_provider.c.dart +++ b/lib/app/services/ion_identity/ion_identity_provider.c.dart @@ -3,26 +3,37 @@ import 'dart:io'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ion/app/features/core/model/feature_flags.dart'; import 'package:ion/app/features/core/providers/env_provider.c.dart'; -import 'package:ion/app/services/logger/config.dart'; +import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; +import 'package:ion/app/services/ion_identity/ion_identity_logger.dart'; import 'package:ion_identity_client/ion_identity.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'ion_identity_provider.c.g.dart'; @Riverpod(keepAlive: true) Future> ionIdentity(Ref ref) async { - await ref.watch(envProvider.future); - final envController = ref.watch(envProvider.notifier); + final env = ref.read(envProvider.notifier); - final appId = envController.get( + final appId = env.get( Platform.isAndroid ? EnvVariable.ION_ANDROID_APP_ID : EnvVariable.ION_IOS_APP_ID, ); + final logIonIdentityClient = + ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logIonIdentityClient); + final config = IONIdentityConfig( appId: appId, - origin: envController.get(EnvVariable.ION_ORIGIN), - logging: LoggerConfig.ionIdentityLogsEnabled, + origin: env.get(EnvVariable.ION_ORIGIN), + logger: logIonIdentityClient + ? IonIdentityLogger( + fileOutput: File( + '${(await getTemporaryDirectory()).path}/${IonIdentityLogger.logFileName}', + ), + ) + : null, ); final ionClient = IONIdentity.createDefault(config: config); diff --git a/lib/app/services/logger/config.dart b/lib/app/services/logger/config.dart deleted file mode 100644 index 596d31536..000000000 --- a/lib/app/services/logger/config.dart +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -class LoggerConfig { - LoggerConfig._(); - - static const bool riverpodLogsEnabled = false; - - static const bool routerLogsEnabled = true; - - static const bool nostrLogsEnabled = true; - - static const bool ionIdentityLogsEnabled = true; - - static const bool dioLogsEnabled = true; -} diff --git a/lib/app/services/logger/logger.dart b/lib/app/services/logger/logger.dart index e5b1fbc2d..1ed7ea805 100644 --- a/lib/app/services/logger/logger.dart +++ b/lib/app/services/logger/logger.dart @@ -1,10 +1,16 @@ // SPDX-License-Identifier: ice License 1.0 import 'dart:developer' as developer; +import 'dart:io'; + +import 'package:path_provider/path_provider.dart'; class Logger { Logger._(); + static String logFileName = 'app_logs.txt'; + static File? _logFile; + static void log( String message, { String name = '', @@ -12,5 +18,38 @@ class Logger { StackTrace? stackTrace, }) { developer.log(message, name: name, error: error, stackTrace: stackTrace); + _writeToLogs(message, name: name, error: error, stackTrace: stackTrace); + } + + static Future _initLogFile() async { + if (_logFile != null) return; + final dir = await getTemporaryDirectory(); + _logFile = File('${dir.path}/$logFileName'); + } + + static Future _writeToLogs( + String message, { + String name = '', + Object? error, + StackTrace? stackTrace, + }) async { + await _initLogFile(); + + final timestamp = DateTime.now().toIso8601String(); + final separator = '=' * 50; + + final logEntry = '$separator\n' + '📝 Log Entry at $timestamp\n' + '${name.isNotEmpty ? '📌 Context: $name\n' : ''}' + '💬 Message: $message\n' + '${error != null ? '❌ Error: $error\n' : ''}' + '${stackTrace != null ? '🔍 Stack Trace:\n$stackTrace\n' : ''}' + '$separator\n\n'; + + try { + await _logFile?.writeAsString(logEntry, mode: FileMode.append); + } catch (e) { + developer.log('Failed to write to log file: $e'); + } } } diff --git a/lib/app/services/media_service/banuba_service.c.dart b/lib/app/services/media_service/banuba_service.c.dart index 73d25b327..97fa8d1c5 100644 --- a/lib/app/services/media_service/banuba_service.c.dart +++ b/lib/app/services/media_service/banuba_service.c.dart @@ -84,7 +84,7 @@ class BanubaService { @riverpod BanubaService banubaService(Ref ref) { - return BanubaService(ref.watch(envProvider.notifier)); + return BanubaService(ref.read(envProvider.notifier)); } @riverpod diff --git a/lib/app/services/nostr/nostr.dart b/lib/app/services/nostr/nostr.dart index ebc4df7f1..5ab323a42 100644 --- a/lib/app/services/nostr/nostr.dart +++ b/lib/app/services/nostr/nostr.dart @@ -1,17 +1,22 @@ // SPDX-License-Identifier: ice License 1.0 -import 'package:ion/app/services/logger/config.dart'; +import 'dart:io'; + +import 'package:ion/app/services/nostr/nostr_logger.dart'; import 'package:ion/app/services/nostr/nostr_signature_verifier.dart'; import 'package:nostr_dart/nostr_dart.dart'; class Nostr { Nostr._(); - static void initialize() { + static void initialize(String? logFilePath) { NostrDart.configure( - // ignore: avoid_redundant_argument_values - logLevel: LoggerConfig.nostrLogsEnabled ? NostrLogLevel.ALL : NostrLogLevel.OFF, signatureVerifier: NostrSignatureVerifier(), + logger: logFilePath != null + ? NostrLogger( + fileOutput: File(logFilePath), + ) + : null, ); } } diff --git a/lib/app/services/nostr/nostr_logger.dart b/lib/app/services/nostr/nostr_logger.dart new file mode 100644 index 000000000..7a1d3e04e --- /dev/null +++ b/lib/app/services/nostr/nostr_logger.dart @@ -0,0 +1,34 @@ +import 'dart:io'; + +import 'package:logger/logger.dart' as log; +import 'package:nostr_dart/nostr_dart.dart'; + +class NostrLogger implements NostrDartLogger { + NostrLogger({File? fileOutput}) + : _log = log.Logger( + printer: log.PrettyPrinter( + methodCount: 0, + lineLength: 1000, + dateTimeFormat: log.DateTimeFormat.dateAndTime, + ), + level: log.Level.all, + output: log.MultiOutput([ + log.ConsoleOutput(), + if (fileOutput != null) log.FileOutput(file: fileOutput), + ]), + ); + + static String logFileName = 'nostr_logs.txt'; + + final log.Logger _log; + + @override + void info(String message, [Object? error, StackTrace? stackTrace]) { + _log.i(message, error: error, stackTrace: stackTrace); + } + + @override + void warning(String message, [Object? error, StackTrace? stackTrace]) { + _log.w(message, error: error, stackTrace: stackTrace); + } +} diff --git a/lib/app/services/riverpod/root_provider_scope.dart b/lib/app/services/riverpod/root_provider_scope.dart index a4467e275..4b92d9a12 100644 --- a/lib/app/services/riverpod/root_provider_scope.dart +++ b/lib/app/services/riverpod/root_provider_scope.dart @@ -2,10 +2,11 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:ion/app/services/logger/config.dart'; import 'package:ion/app/services/riverpod/riverpod_logger.dart'; -class RiverpodRootProviderScope extends StatelessWidget { +const _riverpodLoggerEnabled = false; + +class RiverpodRootProviderScope extends ConsumerWidget { const RiverpodRootProviderScope({ required this.child, super.key, @@ -14,10 +15,10 @@ class RiverpodRootProviderScope extends StatelessWidget { final Widget child; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return ProviderScope( observers: [ - if (LoggerConfig.riverpodLogsEnabled) RiverpodLogger(), + if (_riverpodLoggerEnabled) RiverpodLogger(), ], child: child, ); diff --git a/lib/main.dart b/lib/main.dart index aa2e59bf7..fcf81e038 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_quill/translations.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/core/providers/app_locale_provider.c.dart'; @@ -12,19 +13,20 @@ import 'package:ion/app/features/wallet/components/coin_sync/coins_sync_wrapper. import 'package:ion/app/router/components/app_router_builder.dart'; import 'package:ion/app/router/components/modal_wrapper/sheet_scope.dart'; import 'package:ion/app/router/providers/go_router_provider.c.dart'; -import 'package:ion/app/services/logger/config.dart'; -import 'package:ion/app/services/riverpod/riverpod_logger.dart'; +import 'package:ion/app/services/riverpod/root_provider_scope.dart'; import 'package:ion/app/services/storage/secure_storage.c.dart'; import 'package:ion/app/theme/theme.dart'; import 'package:ion/generated/app_localizations.dart'; +import 'package:ion/generated/assets.gen.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await SecureStorage().clearOnReinstall(); + await dotenv.load(fileName: Assets.aApp); + runApp( - ProviderScope( - observers: [if (LoggerConfig.riverpodLogsEnabled) RiverpodLogger()], - child: const IONApp(), + const RiverpodRootProviderScope( + child: IONApp(), ), ); } diff --git a/packages/ion_identity_client/example/pubspec.lock b/packages/ion_identity_client/example/pubspec.lock index 2ebcaaa19..754b02635 100644 --- a/packages/ion_identity_client/example/pubspec.lock +++ b/packages/ion_identity_client/example/pubspec.lock @@ -772,14 +772,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - pretty_dio_logger: - dependency: transitive - description: - name: pretty_dio_logger - sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407" - url: "https://pub.dev" - source: hosted - version: "1.4.0" pub_semver: dependency: transitive description: diff --git a/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart b/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart index e63c46d90..6cc1212c7 100644 --- a/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart +++ b/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart @@ -9,7 +9,6 @@ import 'package:ion_identity_client/src/core/service_locator/ion_identity_client import 'package:ion_identity_client/src/core/storage/private_key_storage.dart'; import 'package:ion_identity_client/src/core/storage/token_storage.dart'; import 'package:ion_identity_client/src/core/types/request_headers.dart'; -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; class NetworkServiceLocator with _Dio, _Interceptors, _TokenStorage, _PrivateKeyStorage, _NetworkClient { @@ -64,7 +63,7 @@ mixin _Dio { final dio = Dio(dioOptions); final interceptors = [ - if (config.logging) NetworkServiceLocator().loggerInterceptor(), + if (config.logger != null) config.logger!, ]; dio.interceptors.addAll(interceptors); @@ -73,11 +72,15 @@ mixin _Dio { } mixin _Interceptors { + final StringBuffer _logBuffer = StringBuffer(); + String get logs => _logBuffer.toString(); + Iterable interceptors({ required IONIdentityConfig config, }) { + final logger = config.logger; return [ - if (config.logging) loggerInterceptor(), + if (config.logger != null) logger!, authInterceptor(config: config), ]; } @@ -90,13 +93,6 @@ mixin _Interceptors { delegatedLoginService: AuthClientServiceLocator().delegatedLogin(config: config), ); } - - Interceptor loggerInterceptor() { - return PrettyDioLogger( - requestBody: true, - requestHeader: true, - ); - } } mixin _TokenStorage { diff --git a/packages/ion_identity_client/lib/src/ion_identity_config.dart b/packages/ion_identity_client/lib/src/ion_identity_config.dart index 8c39e1240..b16781b29 100644 --- a/packages/ion_identity_client/lib/src/ion_identity_config.dart +++ b/packages/ion_identity_client/lib/src/ion_identity_config.dart @@ -1,5 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import 'package:dio/dio.dart'; + /// A configuration class for the ION Identity client, containing the necessary /// identifiers and origin information required to initialize the client. class IONIdentityConfig { @@ -8,7 +10,7 @@ class IONIdentityConfig { IONIdentityConfig({ required this.appId, required this.origin, - this.logging = false, + this.logger, }); /// The application identifier used to uniquely identify the app within the ION Identity API. @@ -18,9 +20,10 @@ class IONIdentityConfig { /// and securing API requests. final String origin; - /// Whether to enable logging for the ION Identity client. - final bool logging; + /// The logger interceptor to use for logging requests and responses. + final Interceptor? logger; @override - String toString() => 'IONIdentityConfig(appId: $appId, origin: $origin, logging: $logging)'; + String toString() => + 'IONIdentityConfig(appId: $appId, origin: $origin, logger: ${logger?.toString() ?? 'null'})'; } diff --git a/packages/ion_identity_client/pubspec.yaml b/packages/ion_identity_client/pubspec.yaml index c29ece699..88283aad7 100644 --- a/packages/ion_identity_client/pubspec.yaml +++ b/packages/ion_identity_client/pubspec.yaml @@ -22,7 +22,6 @@ dependencies: local_auth: ^2.3.0 passkeys: ^2.1.0 pointycastle: ^3.9.1 - pretty_dio_logger: ^1.4.0 rxdart: ^0.28.0 sprintf: ^7.0.0 uuid: ^4.5.1 diff --git a/pubspec.lock b/pubspec.lock index 2ebccb08b..ee5c93e6b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -98,10 +98,10 @@ packages: dependency: transitive description: name: bip340 - sha256: "2a92f6ed68959f75d67c9a304c17928b9c9449587d4f75ee68f34152f7f69e87" + sha256: b7bcd70a860e605046006adaa72bc4f7453f4d31d7ba74a4ad9d5de387a0fc0b url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.3.0" boolean_selector: dependency: transitive description: @@ -346,10 +346,10 @@ packages: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" crypto_keys: dependency: transitive description: @@ -546,10 +546,10 @@ packages: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" es_compression: dependency: "direct main" description: @@ -1018,14 +1018,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" - get_it: - dependency: transitive - description: - name: get_it - sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 - url: "https://pub.dev" - source: hosted - version: "7.7.0" glob: dependency: transitive description: @@ -1345,7 +1337,7 @@ packages: source: hosted version: "1.0.11" logger: - dependency: transitive + dependency: "direct main" description: name: logger sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 @@ -1469,11 +1461,11 @@ packages: dependency: "direct main" description: path: "." - ref: "0.0.17" - resolved-ref: "4dcd288c2c842725fa2cb096cb43142f8f1a390d" + ref: "0.0.18" + resolved-ref: ae7a435d3eb28edc177a34004edbb523ba9ed264 url: "https://github.com/ice-blockchain/nostr-dart.git" source: git - version: "0.0.17" + version: "0.0.18" octo_image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3f6490946..f301d4c08 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,6 +58,7 @@ dependencies: ion_screenshot_detector: path: packages/ion_screenshot_detector json_annotation: ^4.8.1 + logger: ^2.5.0 lottie: ^3.1.0 markdown_quill: ^4.1.0 meta: ^1.15.0 @@ -70,7 +71,7 @@ dependencies: nostr_dart: git: url: https://github.com/ice-blockchain/nostr-dart.git - ref: 0.0.17 + ref: 0.0.18 ogp_data_extract: ^0.1.4 package_info_plus: ^4.2.0 path: ^1.9.0 diff --git a/test/user/follow_list_test.dart b/test/user/follow_list_test.dart index 35dd98e73..47d590086 100644 --- a/test/user/follow_list_test.dart +++ b/test/user/follow_list_test.dart @@ -6,7 +6,7 @@ import 'package:ion/app/services/nostr/ed25519_key_store.dart'; import 'package:nostr_dart/nostr_dart.dart'; void main() { - NostrDart.configure(logLevel: NostrLogLevel.ALL); + NostrDart.configure(); group('FollowList Tests', () { test('FollowList.fromEventMessage should work when all data is there', () async { diff --git a/test/user/interests_set_test.dart b/test/user/interests_set_test.dart index 8ba69e9dc..14918fb59 100644 --- a/test/user/interests_set_test.dart +++ b/test/user/interests_set_test.dart @@ -6,7 +6,7 @@ import 'package:ion/app/services/nostr/ed25519_key_store.dart'; import 'package:nostr_dart/nostr_dart.dart'; void main() { - NostrDart.configure(logLevel: NostrLogLevel.ALL); + NostrDart.configure(); group('InterestsSet Tests', () { test('InterestSet.fromEventMessage should work when all data is there', () async { diff --git a/test/user/interests_test.dart b/test/user/interests_test.dart index ca72e6223..8ecb8ea28 100644 --- a/test/user/interests_test.dart +++ b/test/user/interests_test.dart @@ -7,7 +7,7 @@ import 'package:ion/app/services/nostr/ed25519_key_store.dart'; import 'package:nostr_dart/nostr_dart.dart'; void main() { - NostrDart.configure(logLevel: NostrLogLevel.ALL); + NostrDart.configure(); group('Interests Tests', () { test('Interests.fromEventMessage should work when all data is there', () async { diff --git a/test/user/user_delegation_test.dart b/test/user/user_delegation_test.dart index 61dead59e..f104715c2 100644 --- a/test/user/user_delegation_test.dart +++ b/test/user/user_delegation_test.dart @@ -7,7 +7,7 @@ import 'package:nostr_dart/nostr_dart.dart'; void main() { const pubkey = '477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396'; - NostrDart.configure(logLevel: NostrLogLevel.ALL); + NostrDart.configure(); group('UserDelegation Tests', () { test('UserDelegation.fromEventMessage should work when all data is there', () async { From 0acaa403da060acee57cc12f592a07600a510f5e Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:01:51 +0100 Subject: [PATCH 02/11] feat: add debug page --- .../discover_creators/discover_creators.dart | 2 +- .../core/providers/dio_provider.c.dart | 8 +- .../providers/feature_flags_provider.c.dart | 75 ++------------- .../core/providers/init_provider.c.dart | 5 +- lib/app/features/debug/views/debug_page.dart | 92 +++++++------------ .../components/loaders/grid_loader.dart | 2 +- .../components/nfts/nfts_tab_footer.dart | 2 +- lib/app/router/app_routes.c.dart | 1 + .../providers/go_router_provider.c.dart | 2 +- .../ion_identity/ion_identity_logger.dart | 20 ---- .../ion_identity/ion_identity_provider.c.dart | 13 +-- lib/app/services/logger/logger.dart | 64 ++++++------- lib/app/services/nostr/nostr.dart | 10 +- lib/app/services/nostr/nostr_logger.dart | 34 +++---- .../services/riverpod/riverpod_logger.dart | 57 ------------ .../riverpod/root_provider_scope.dart | 4 +- pubspec.lock | 72 +++++++++++---- pubspec.yaml | 5 +- 18 files changed, 158 insertions(+), 310 deletions(-) delete mode 100644 lib/app/services/ion_identity/ion_identity_logger.dart delete mode 100644 lib/app/services/riverpod/riverpod_logger.dart diff --git a/lib/app/features/auth/views/pages/discover_creators/discover_creators.dart b/lib/app/features/auth/views/pages/discover_creators/discover_creators.dart index 4ca89a1f3..5473e84f5 100644 --- a/lib/app/features/auth/views/pages/discover_creators/discover_creators.dart +++ b/lib/app/features/auth/views/pages/discover_creators/discover_creators.dart @@ -37,7 +37,7 @@ class DiscoverCreators extends HookConsumerWidget { final contentCreators = entitiesPagedData?.data.items?.whereType(); final hideCreatorsWithoutPicture = ref - .watch(featureFlagsProvider.notifier) + .read(featureFlagsProvider.notifier) .get(HideCreatorsWithoutPicture.hideCreatorsWithoutPicture); final filteredCreators = hideCreatorsWithoutPicture diff --git a/lib/app/features/core/providers/dio_provider.c.dart b/lib/app/features/core/providers/dio_provider.c.dart index 01548d628..6c6bedede 100644 --- a/lib/app/features/core/providers/dio_provider.c.dart +++ b/lib/app/features/core/providers/dio_provider.c.dart @@ -4,19 +4,21 @@ import 'package:dio/dio.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/core/model/feature_flags.dart'; import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +import 'package:ion/app/services/logger/logger.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'dio_provider.c.g.dart'; @riverpod Dio dio(Ref ref) { - final logApp = ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logApp); + final logApp = ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logApp); final dio = Dio(); if (logApp) { - dio.interceptors.add(PrettyDioLogger()); + dio.interceptors.add( + Logger.talkerDioLogger, + ); } return dio; diff --git a/lib/app/features/core/providers/feature_flags_provider.c.dart b/lib/app/features/core/providers/feature_flags_provider.c.dart index 2f8e247ae..31ff0d35a 100644 --- a/lib/app/features/core/providers/feature_flags_provider.c.dart +++ b/lib/app/features/core/providers/feature_flags_provider.c.dart @@ -1,87 +1,28 @@ // SPDX-License-Identifier: ice License 1.0 import 'package:ion/app/features/core/model/feature_flags.dart'; -import 'package:ion/app/features/core/providers/env_provider.c.dart'; -import 'package:ion/app/services/logger/logger.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'feature_flags_provider.c.g.dart'; -abstract class FeatureFlagsService { - const FeatureFlagsService(); - - bool? get(FeatureFlag flag); - - Set get supportedFlags; -} - -final class LocalFeatureFlagsService extends FeatureFlagsService { - factory LocalFeatureFlagsService() { - return const LocalFeatureFlagsService._({ +@Riverpod(keepAlive: true) +class FeatureFlags extends _$FeatureFlags { + @override + Map build() { + return { + /// Local flags WalletFeatureFlag.buyNftEnabled: false, FeedFeatureFlag.showTrendingVideo: false, FeedFeatureFlag.showMentionsSuggestions: false, HideCreatorsWithoutPicture.hideCreatorsWithoutPicture: true, - }); - } - const LocalFeatureFlagsService._(this._featuresMap); - - final Map _featuresMap; - - @override - bool? get(FeatureFlag flag) => _featuresMap[flag]; - - @override - Set get supportedFlags => _featuresMap.keys.toSet(); -} - -final class LoggerFeatureFlagsService extends FeatureFlagsService { - factory LoggerFeatureFlagsService() { - return const LoggerFeatureFlagsService._({ + /// Log flags LoggerFeatureFlag.logApp: true, LoggerFeatureFlag.logRouters: false, LoggerFeatureFlag.logNostrDart: true, LoggerFeatureFlag.logIonIdentityClient: true, - }); - } - - const LoggerFeatureFlagsService._(this._featuresMap); - - final Map _featuresMap; - - @override - bool? get(FeatureFlag flag) => _featuresMap[flag]; - - @override - Set get supportedFlags => _featuresMap.keys.toSet(); -} - -@Riverpod(keepAlive: true) -class FeatureFlags extends _$FeatureFlags { - @override - Set build() { - final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); - - return { - LocalFeatureFlagsService(), - if (showDebugInfo) LoggerFeatureFlagsService(), }; } - bool get(FeatureFlag flag, {bool defaultValue = false}) { - for (final service in state) { - if (service.supportedFlags.contains(flag)) { - final value = service.get(flag); - - if (value != null) { - return value; - } - } - } - - Logger.log('${flag.key} not found.'); - - return defaultValue; - } + bool get(FeatureFlag flag) => state[flag] ?? false; } diff --git a/lib/app/features/core/providers/init_provider.c.dart b/lib/app/features/core/providers/init_provider.c.dart index a5c97425f..70eacd417 100644 --- a/lib/app/features/core/providers/init_provider.c.dart +++ b/lib/app/features/core/providers/init_provider.c.dart @@ -12,17 +12,16 @@ import 'package:ion/app/features/wallet/data/coins/domain/coin_initializer.c.dar import 'package:ion/app/services/nostr/nostr.dart'; import 'package:ion/app/services/nostr/nostr_logger.dart'; import 'package:ion/app/services/storage/local_storage.c.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'init_provider.c.g.dart'; @Riverpod(keepAlive: true) Future initApp(Ref ref) async { - final logNostrDart = ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logNostrDart); + final logNostrDart = ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logNostrDart); Nostr.initialize( - logNostrDart ? '${(await getTemporaryDirectory()).path}/${NostrLogger.logFileName}' : null, + logNostrDart ? NostrLogger() : null, ); await Future.wait([ diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index 857b23095..94bd09667 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -1,19 +1,17 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart'; -import 'package:ion/app/services/ion_identity/ion_identity_logger.dart'; import 'package:ion/app/services/logger/logger.dart'; -import 'package:ion/app/services/nostr/nostr_logger.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:share_plus/share_plus.dart'; +import 'package:talker_flutter/talker_flutter.dart'; class DebugPage extends ConsumerWidget { const DebugPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { + final featureFlags = ref.watch(featureFlagsProvider); + return Scaffold( appBar: NavigationAppBar.screen( title: const Text('🐞 Debug'), @@ -22,61 +20,37 @@ class DebugPage extends ConsumerWidget { padding: const EdgeInsets.all(16), child: ListView( children: [ - ExpansionTile( - title: const Text('Logs'), - children: [ - ListTile( - title: const Text('App logs'), - onTap: () async { - final tempDir = await getTemporaryDirectory(); - final file = File('${tempDir.path}/${Logger.logFileName}'); - - if (file.existsSync()) { - await Share.shareXFiles([XFile(file.path)]); - } else if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('No logs found'), - ), - ); - } - }, - ), - ListTile( - title: const Text('ION Identity Client'), - onTap: () async { - final tempDir = await getTemporaryDirectory(); - final file = File('${tempDir.path}/${IonIdentityLogger.logFileName}'); - - if (file.existsSync()) { - await Share.shareXFiles([XFile(file.path)]); - } else if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('No logs found'), - ), - ); - } - }, + Card( + child: ListTile( + leading: const Icon(Icons.bug_report), + title: const Text('View Debug Logs'), + subtitle: const Text('Check application logs and diagnostics'), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => TalkerScreen( + talker: Logger.talker, + ), + ), ), - ListTile( - title: const Text('Nostr'), - onTap: () async { - final tempDir = await getTemporaryDirectory(); - final file = File('${tempDir.path}/${NostrLogger.logFileName}'); - - if (file.existsSync()) { - await Share.shareXFiles([XFile(file.path)]); - } else if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('No logs found'), + ), + ), + ExpansionTile( + title: const Text('Feature Flags'), + children: featureFlags.entries + .map( + (entry) => Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + title: Text(entry.key.key), + trailing: Icon( + entry.value ? Icons.check_circle : Icons.cancel, + color: entry.value ? Colors.green : Colors.red, ), - ); - } - }, - ), - ], + ), + ), + ) + .toList(), ), ], ), diff --git a/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart b/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart index 3e6fc28d0..5457299c4 100644 --- a/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart +++ b/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart @@ -16,7 +16,7 @@ class GridLoader extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final buyNftFeatureEnabled = - ref.watch(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); + ref.read(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); final width = (MediaQuery.sizeOf(context).width - ScreenSideOffset.defaultSmallMargin * 2 - 12.0.s) / 2; diff --git a/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart b/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart index 467c251f1..00b739fba 100644 --- a/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart +++ b/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart @@ -21,7 +21,7 @@ class NftsTabFooter extends ConsumerWidget { final searchVisibleProvider = walletSearchVisibilityProvider(tabType); final isSearchVisible = ref.watch(searchVisibleProvider); final buyNftFeatureEnabled = - ref.watch(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); + ref.read(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); return SliverToBoxAdapter( child: buyNftFeatureEnabled && !isSearchVisible diff --git a/lib/app/router/app_routes.c.dart b/lib/app/router/app_routes.c.dart index c8db88155..963f2823d 100644 --- a/lib/app/router/app_routes.c.dart +++ b/lib/app/router/app_routes.c.dart @@ -38,6 +38,7 @@ import 'package:ion/app/features/core/views/photo_gallery_page/photo_gallery_pag import 'package:ion/app/features/dapps/views/pages/dapp_details/dapp_details_modal.dart'; import 'package:ion/app/features/dapps/views/pages/dapps.dart'; import 'package:ion/app/features/dapps/views/pages/dapps_list/dapps_list.dart'; +import 'package:ion/app/features/debug/views/debug_page.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_modal/create_article_modal.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/create_article_topics.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/create_article_preview_modal.dart'; diff --git a/lib/app/router/providers/go_router_provider.c.dart b/lib/app/router/providers/go_router_provider.c.dart index 3ed056078..8cec5edf8 100644 --- a/lib/app/router/providers/go_router_provider.c.dart +++ b/lib/app/router/providers/go_router_provider.c.dart @@ -50,7 +50,7 @@ GoRouter goRouter(Ref ref) { routes: $appRoutes, errorBuilder: (context, state) => ErrorPage(error: state.error ?? Exception('Unknown error')), initialLocation: SplashRoute().location, - debugLogDiagnostics: ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logRouters), + debugLogDiagnostics: ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logRouters), navigatorKey: rootNavigatorKey, ); } diff --git a/lib/app/services/ion_identity/ion_identity_logger.dart b/lib/app/services/ion_identity/ion_identity_logger.dart deleted file mode 100644 index 34d892ab9..000000000 --- a/lib/app/services/ion_identity/ion_identity_logger.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:developer' as developer; -import 'dart:io'; - -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; - -class IonIdentityLogger extends PrettyDioLogger { - IonIdentityLogger({File? fileOutput}) - : super( - requestBody: true, - requestHeader: true, - logPrint: fileOutput != null - ? (message) { - fileOutput.writeAsStringSync('$message\n', mode: FileMode.append); - developer.log(message.toString()); - } - : (Object message) => developer.log(message.toString()), - ); - - static const logFileName = 'ion_identity_client_logs.txt'; -} diff --git a/lib/app/services/ion_identity/ion_identity_provider.c.dart b/lib/app/services/ion_identity/ion_identity_provider.c.dart index d86606814..18ae07e4d 100644 --- a/lib/app/services/ion_identity/ion_identity_provider.c.dart +++ b/lib/app/services/ion_identity/ion_identity_provider.c.dart @@ -6,9 +6,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/core/model/feature_flags.dart'; import 'package:ion/app/features/core/providers/env_provider.c.dart'; import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; -import 'package:ion/app/services/ion_identity/ion_identity_logger.dart'; +import 'package:ion/app/services/logger/logger.dart'; import 'package:ion_identity_client/ion_identity.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'ion_identity_provider.c.g.dart'; @@ -22,18 +21,12 @@ Future> ionIdentity(Ref ref) async { ); final logIonIdentityClient = - ref.watch(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logIonIdentityClient); + ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logIonIdentityClient); final config = IONIdentityConfig( appId: appId, origin: env.get(EnvVariable.ION_ORIGIN), - logger: logIonIdentityClient - ? IonIdentityLogger( - fileOutput: File( - '${(await getTemporaryDirectory()).path}/${IonIdentityLogger.logFileName}', - ), - ) - : null, + logger: logIonIdentityClient ? Logger.talkerDioLogger : null, ); final ionClient = IONIdentity.createDefault(config: config); diff --git a/lib/app/services/logger/logger.dart b/lib/app/services/logger/logger.dart index 1ed7ea805..835d990a3 100644 --- a/lib/app/services/logger/logger.dart +++ b/lib/app/services/logger/logger.dart @@ -1,55 +1,45 @@ // SPDX-License-Identifier: ice License 1.0 -import 'dart:developer' as developer; -import 'dart:io'; - -import 'package:path_provider/path_provider.dart'; +import 'package:talker_dio_logger/talker_dio_logger_interceptor.dart'; +import 'package:talker_dio_logger/talker_dio_logger_settings.dart'; +import 'package:talker_flutter/talker_flutter.dart'; class Logger { Logger._(); - static String logFileName = 'app_logs.txt'; - static File? _logFile; + static final Talker talker = TalkerFlutter.init(); + + static final talkerDioLogger = TalkerDioLogger( + talker: talker, + settings: TalkerDioLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + requestPen: AnsiPen()..cyan(), + responsePen: AnsiPen()..green(), + errorPen: AnsiPen()..red(), + ), + ); static void log( String message, { - String name = '', Object? error, StackTrace? stackTrace, }) { - developer.log(message, name: name, error: error, stackTrace: stackTrace); - _writeToLogs(message, name: name, error: error, stackTrace: stackTrace); - } + talker.log(message); - static Future _initLogFile() async { - if (_logFile != null) return; - final dir = await getTemporaryDirectory(); - _logFile = File('${dir.path}/$logFileName'); + if (error != null) { + talker.error(error, stackTrace); + } } - static Future _writeToLogs( - String message, { - String name = '', - Object? error, + static void info(String message) => talker.info(message); + + static void warning(String message) => talker.warning(message); + + static void error( + Object error, { StackTrace? stackTrace, - }) async { - await _initLogFile(); - - final timestamp = DateTime.now().toIso8601String(); - final separator = '=' * 50; - - final logEntry = '$separator\n' - '📝 Log Entry at $timestamp\n' - '${name.isNotEmpty ? '📌 Context: $name\n' : ''}' - '💬 Message: $message\n' - '${error != null ? '❌ Error: $error\n' : ''}' - '${stackTrace != null ? '🔍 Stack Trace:\n$stackTrace\n' : ''}' - '$separator\n\n'; - - try { - await _logFile?.writeAsString(logEntry, mode: FileMode.append); - } catch (e) { - developer.log('Failed to write to log file: $e'); - } + }) { + talker.error(error, stackTrace); } } diff --git a/lib/app/services/nostr/nostr.dart b/lib/app/services/nostr/nostr.dart index 5ab323a42..55c464427 100644 --- a/lib/app/services/nostr/nostr.dart +++ b/lib/app/services/nostr/nostr.dart @@ -1,7 +1,5 @@ // SPDX-License-Identifier: ice License 1.0 -import 'dart:io'; - import 'package:ion/app/services/nostr/nostr_logger.dart'; import 'package:ion/app/services/nostr/nostr_signature_verifier.dart'; import 'package:nostr_dart/nostr_dart.dart'; @@ -9,14 +7,10 @@ import 'package:nostr_dart/nostr_dart.dart'; class Nostr { Nostr._(); - static void initialize(String? logFilePath) { + static void initialize(NostrLogger? logger) { NostrDart.configure( signatureVerifier: NostrSignatureVerifier(), - logger: logFilePath != null - ? NostrLogger( - fileOutput: File(logFilePath), - ) - : null, + logger: logger, ); } } diff --git a/lib/app/services/nostr/nostr_logger.dart b/lib/app/services/nostr/nostr_logger.dart index 7a1d3e04e..85d37fa52 100644 --- a/lib/app/services/nostr/nostr_logger.dart +++ b/lib/app/services/nostr/nostr_logger.dart @@ -1,34 +1,24 @@ -import 'dart:io'; - -import 'package:logger/logger.dart' as log; +import 'package:ion/app/services/logger/logger.dart'; import 'package:nostr_dart/nostr_dart.dart'; class NostrLogger implements NostrDartLogger { - NostrLogger({File? fileOutput}) - : _log = log.Logger( - printer: log.PrettyPrinter( - methodCount: 0, - lineLength: 1000, - dateTimeFormat: log.DateTimeFormat.dateAndTime, - ), - level: log.Level.all, - output: log.MultiOutput([ - log.ConsoleOutput(), - if (fileOutput != null) log.FileOutput(file: fileOutput), - ]), - ); - - static String logFileName = 'nostr_logs.txt'; - - final log.Logger _log; + static const _prefix = '🦩 Nostr:'; @override void info(String message, [Object? error, StackTrace? stackTrace]) { - _log.i(message, error: error, stackTrace: stackTrace); + Logger.info('$_prefix $message'); + + if (error != null) { + Logger.error('$_prefix $error', stackTrace: stackTrace); + } } @override void warning(String message, [Object? error, StackTrace? stackTrace]) { - _log.w(message, error: error, stackTrace: stackTrace); + Logger.warning('$_prefix $message'); + + if (error != null) { + Logger.error('$_prefix $error', stackTrace: stackTrace); + } } } diff --git a/lib/app/services/riverpod/riverpod_logger.dart b/lib/app/services/riverpod/riverpod_logger.dart deleted file mode 100644 index f3f31ca73..000000000 --- a/lib/app/services/riverpod/riverpod_logger.dart +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:ion/app/services/logger/logger.dart'; - -class RiverpodLogger extends ProviderObserver { - static const String tag = 'Riverpod'; - - @override - void didAddProvider( - ProviderBase provider, - Object? value, - ProviderContainer container, - ) { - _log('Provider $provider was initialized with $value'); - } - - @override - void didDisposeProvider( - ProviderBase provider, - ProviderContainer container, - ) { - _log('Provider $provider was disposed'); - } - - @override - void didUpdateProvider( - ProviderBase provider, - Object? previousValue, - Object? newValue, - ProviderContainer container, - ) { - _log('Provider $provider updated from $previousValue to $newValue'); - } - - @override - void providerDidFail( - ProviderBase provider, - Object error, - StackTrace stackTrace, - ProviderContainer container, - ) { - _log( - 'Provider $provider threw error', - error: error, - stackTrace: stackTrace, - ); - } - - void _log( - String message, { - Object? error, - StackTrace? stackTrace, - }) { - Logger.log(message, name: tag, error: error, stackTrace: stackTrace); - } -} diff --git a/lib/app/services/riverpod/root_provider_scope.dart b/lib/app/services/riverpod/root_provider_scope.dart index 4b92d9a12..538d2db7a 100644 --- a/lib/app/services/riverpod/root_provider_scope.dart +++ b/lib/app/services/riverpod/root_provider_scope.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:ion/app/services/riverpod/riverpod_logger.dart'; +import 'package:talker_riverpod_logger/talker_riverpod_logger_observer.dart'; const _riverpodLoggerEnabled = false; @@ -18,7 +18,7 @@ class RiverpodRootProviderScope extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return ProviderScope( observers: [ - if (_riverpodLoggerEnabled) RiverpodLogger(), + if (_riverpodLoggerEnabled) TalkerRiverpodObserver(), ], child: child, ); diff --git a/pubspec.lock b/pubspec.lock index ee5c93e6b..8b16b8868 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -46,6 +46,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.2+1" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" archive: dependency: transitive description: @@ -1050,6 +1058,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + group_button: + dependency: transitive + description: + name: group_button + sha256: "0610fcf28ed122bfb4b410fce161a390f7f2531d55d1d65c5375982001415940" + url: "https://pub.dev" + source: hosted + version: "5.3.4" hashcodes: dependency: transitive description: @@ -1336,14 +1352,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.11" - logger: - dependency: "direct main" - description: - name: logger - sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 - url: "https://pub.dev" - source: hosted - version: "2.5.0" logging: dependency: transitive description: @@ -1723,14 +1731,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - pretty_dio_logger: - dependency: "direct main" - description: - name: pretty_dio_logger - sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407" - url: "https://pub.dev" - source: hosted - version: "1.4.0" process: dependency: transitive description: @@ -2137,6 +2137,46 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0+1" + talker: + dependency: transitive + description: + name: talker + sha256: dff22de27ac0dbe1bb2052fc258ccceee0a2703e6cfe03839ccd337aaf5d291b + url: "https://pub.dev" + source: hosted + version: "4.6.0" + talker_dio_logger: + dependency: "direct main" + description: + name: talker_dio_logger + sha256: "365f42501e32af3cb91050af01d8de0c1c0a6ec72b74c48d18d5ea25982de210" + url: "https://pub.dev" + source: hosted + version: "4.5.4" + talker_flutter: + dependency: "direct main" + description: + name: talker_flutter + sha256: "7dce55a42ffe9ac590d46f71a978aa1eb7aecd040915a8307f8880526c47f9ae" + url: "https://pub.dev" + source: hosted + version: "4.5.4" + talker_logger: + dependency: transitive + description: + name: talker_logger + sha256: f6af15f038576fb727668131c2a829f986bab0bad379e48805a8f251e3687002 + url: "https://pub.dev" + source: hosted + version: "4.6.0" + talker_riverpod_logger: + dependency: "direct main" + description: + name: talker_riverpod_logger + sha256: "3675743a5f78fb36bb060fda1a313efe3ee3bf16e999c7163cd5893b11a2aaf8" + url: "https://pub.dev" + source: hosted + version: "4.5.4" term_glyph: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f301d4c08..2b2419700 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,7 +58,6 @@ dependencies: ion_screenshot_detector: path: packages/ion_screenshot_detector json_annotation: ^4.8.1 - logger: ^2.5.0 lottie: ^3.1.0 markdown_quill: ^4.1.0 meta: ^1.15.0 @@ -79,7 +78,6 @@ dependencies: permission_handler: ^11.3.0 photo_manager: ^3.6.3 photo_manager_image_provider: ^2.1.1 - pretty_dio_logger: ^1.4.0 qr_code_scanner: git: url: https://github.com/ice-blockchain/qr_code_scanner @@ -91,6 +89,9 @@ dependencies: shared_preferences: ^2.2.2 shimmer: ^3.0.0 smooth_sheets: ^1.0.0-f324.0.10.2 + talker_dio_logger: 4.5.4 + talker_flutter: 4.5.4 + talker_riverpod_logger: 4.5.4 timeago: ^3.6.1 timeago_flutter: ^3.6.0 uri_to_file: ^1.0.0 From 0427f767008e3187cf3fc1737fdef7af6ded4ba2 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:07:36 +0100 Subject: [PATCH 03/11] feat: add shake gesture --- .../main/kotlin/io/ion/app/MainActivity.kt | 14 ++++++- ios/Podfile.lock | 12 ++++-- lib/app/features/debug/views/debug_page.dart | 2 + .../debug/views/debug_shake_gesture.dart | 38 +++++++++++++++++++ lib/app/router/app_routes.c.dart | 1 - .../router/components/app_router_builder.dart | 5 ++- .../router/main_tabs/main_tab_navigation.dart | 11 ------ lib/app/services/nostr/nostr_logger.dart | 2 + pubspec.lock | 32 ++++++++++++++++ pubspec.yaml | 1 + 10 files changed, 101 insertions(+), 17 deletions(-) create mode 100644 lib/app/features/debug/views/debug_shake_gesture.dart diff --git a/android/app/src/main/kotlin/io/ion/app/MainActivity.kt b/android/app/src/main/kotlin/io/ion/app/MainActivity.kt index 03717d17c..6d1f8fe9f 100644 --- a/android/app/src/main/kotlin/io/ion/app/MainActivity.kt +++ b/android/app/src/main/kotlin/io/ion/app/MainActivity.kt @@ -3,15 +3,27 @@ package io.ion.app import android.content.Intent import android.net.Uri import android.os.Bundle -import com.banuba.sdk.pe.PhotoCreationActivity +import android.view.KeyEvent import com.banuba.sdk.pe.BanubaPhotoEditor +import com.banuba.sdk.pe.PhotoCreationActivity import com.banuba.sdk.pe.data.PhotoEditorConfig +import dev.fluttercommunity.shake_gesture_android.ShakeGesturePlugin import io.flutter.embedding.android.FlutterActivity import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant import java.io.File class MainActivity : FlutterActivity() { + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + if (keyCode == KeyEvent.KEYCODE_MENU) { + this.flutterEngine?.plugins?.get(ShakeGesturePlugin::class.java).let { plugin -> + if (plugin is ShakeGesturePlugin) + plugin.onShake() + } + } + + return super.onKeyDown(keyCode, event) + } companion object { // For Photo Editor diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0fe719dcf..4d85be630 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -161,6 +161,8 @@ PODS: - SDWebImage (5.20.0): - SDWebImage/Core (= 5.20.0) - SDWebImage/Core (5.20.0) + - shake_gesture_ios (0.0.1): + - Flutter - share_plus (0.0.1): - Flutter - shared_preferences_foundation (0.0.1): @@ -241,6 +243,7 @@ DEPENDENCIES: - photo_manager (from `.symlinks/plugins/photo_manager/ios`) - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) - quill_native_bridge (from `.symlinks/plugins/quill_native_bridge/ios`) + - shake_gesture_ios (from `.symlinks/plugins/shake_gesture_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `.symlinks/plugins/sqflite/darwin`) @@ -333,6 +336,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/qr_code_scanner/ios" quill_native_bridge: :path: ".symlinks/plugins/quill_native_bridge/ios" + shake_gesture_ios: + :path: ".symlinks/plugins/shake_gesture_ios/ios" share_plus: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: @@ -400,9 +405,10 @@ SPEC CHECKSUMS: qr_code_scanner: d77f94ecc9abf96d9b9b8fc04ef13f611e5a147a quill_native_bridge: fd2819cf6da02fb6cbf9de37835f96e798e145eb SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 - share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 - sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3 + shake_gesture_ios: 64f1f579f314c58445761992a123111b3d7b3492 + share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71 sqlite3_flutter_libs: f0b59f6bb2a18597d0796558725007e5a7428397 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index 94bd09667..095e37168 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: ice License 1.0 + import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; diff --git a/lib/app/features/debug/views/debug_shake_gesture.dart b/lib/app/features/debug/views/debug_shake_gesture.dart new file mode 100644 index 000000000..efbe6b4e5 --- /dev/null +++ b/lib/app/features/debug/views/debug_shake_gesture.dart @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: ice License 1.0 + +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ion/app/features/core/providers/env_provider.c.dart'; +import 'package:ion/app/features/debug/views/debug_page.dart'; +import 'package:shake_gesture/shake_gesture.dart'; + +class DebugShakeGesture extends ConsumerWidget { + const DebugShakeGesture({ + required this.child, + super.key, + }); + + final Widget child; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); + + return showDebugInfo + ? Navigator( + onGenerateRoute: (settings) => MaterialPageRoute( + builder: (context) => ShakeGesture( + onShake: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const DebugPage(), + ), + ); + }, + child: child, + ), + ), + ) + : child; + } +} diff --git a/lib/app/router/app_routes.c.dart b/lib/app/router/app_routes.c.dart index 963f2823d..c8db88155 100644 --- a/lib/app/router/app_routes.c.dart +++ b/lib/app/router/app_routes.c.dart @@ -38,7 +38,6 @@ import 'package:ion/app/features/core/views/photo_gallery_page/photo_gallery_pag import 'package:ion/app/features/dapps/views/pages/dapp_details/dapp_details_modal.dart'; import 'package:ion/app/features/dapps/views/pages/dapps.dart'; import 'package:ion/app/features/dapps/views/pages/dapps_list/dapps_list.dart'; -import 'package:ion/app/features/debug/views/debug_page.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_modal/create_article_modal.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/components/create_article_topics.dart'; import 'package:ion/app/features/feed/create_article/views/pages/create_article_preview_modal/create_article_preview_modal.dart'; diff --git a/lib/app/router/components/app_router_builder.dart b/lib/app/router/components/app_router_builder.dart index f2324016e..e2d42834c 100644 --- a/lib/app/router/components/app_router_builder.dart +++ b/lib/app/router/components/app_router_builder.dart @@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/components/global_notification_bar/global_notification_bar.dart'; import 'package:ion/app/components/global_notification_bar/providers/global_notification_provider.c.dart'; import 'package:ion/app/extensions/extensions.dart'; +import 'package:ion/app/features/debug/views/debug_shake_gesture.dart'; import 'package:ion/app/hooks/use_interval.dart'; import 'package:ion/app/services/ui_event_queue/ui_event_queue_listener.dart'; @@ -41,7 +42,9 @@ class AppRouterBuilder extends HookConsumerWidget { const GlobalNotificationBar(), const UiEventQueueListener(), Expanded( - child: child ?? const SizedBox.shrink(), + child: DebugShakeGesture( + child: child ?? const SizedBox.shrink(), + ), ), ], ), diff --git a/lib/app/router/main_tabs/main_tab_navigation.dart b/lib/app/router/main_tabs/main_tab_navigation.dart index a1a14a9dc..b8fdca71c 100644 --- a/lib/app/router/main_tabs/main_tab_navigation.dart +++ b/lib/app/router/main_tabs/main_tab_navigation.dart @@ -9,8 +9,6 @@ import 'package:ion/app/extensions/extensions.dart'; import 'package:ion/app/features/chat/providers/user_chat_relays_provider.c.dart'; import 'package:ion/app/features/chat/recent_chats/providers/conversations_edit_mode_provider.c.dart'; import 'package:ion/app/features/chat/recent_chats/views/components/conversation_edit_bottom_bar/conversation_edit_bottom_bar.dart'; -import 'package:ion/app/features/core/providers/env_provider.c.dart'; -import 'package:ion/app/features/debug/views/debug_page.dart'; import 'package:ion/app/hooks/use_on_init.dart'; import 'package:ion/app/router/main_tabs/components/components.dart'; @@ -108,15 +106,6 @@ class _BottomNavBarContent extends ConsumerWidget { child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () => onTabPressed(tabItem), - onLongPress: - ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO) && - tabItem == TabItem.profile - ? () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const DebugPage(), - ), - ) - : null, child: Container( padding: EdgeInsets.symmetric(vertical: 9.0.s), color: context.theme.appColors.secondaryBackground, diff --git a/lib/app/services/nostr/nostr_logger.dart b/lib/app/services/nostr/nostr_logger.dart index 85d37fa52..d17f2acc0 100644 --- a/lib/app/services/nostr/nostr_logger.dart +++ b/lib/app/services/nostr/nostr_logger.dart @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: ice License 1.0 + import 'package:ion/app/services/logger/logger.dart'; import 'package:nostr_dart/nostr_dart.dart'; diff --git a/pubspec.lock b/pubspec.lock index 8b16b8868..9e9795e70 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1900,6 +1900,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.9" + shake_gesture: + dependency: "direct main" + description: + name: shake_gesture + sha256: "943a24bbb34c9c23036d78d60934553435649aa6a8c86ac1b1d58d00ca5f5d06" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + shake_gesture_android: + dependency: transitive + description: + name: shake_gesture_android + sha256: cca62005b4a3beff16fe023e25ec70eee9cfbb1bef215dc1ff5b8a030c3b7fce + url: "https://pub.dev" + source: hosted + version: "1.1.4" + shake_gesture_ios: + dependency: transitive + description: + name: shake_gesture_ios + sha256: dd7d5a89587f3696d2abe45d35c350e9986ebaa723538892e6da91d4c7e092d5 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + shake_gesture_platform_interface: + dependency: transitive + description: + name: shake_gesture_platform_interface + sha256: c5e9adef94892c16e030aabd2c480620cac4dfc002f397309e796248a2a397cc + url: "https://pub.dev" + source: hosted + version: "1.0.1" share_plus: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2b2419700..3891f4860 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -85,6 +85,7 @@ dependencies: version: ^1.0.0 qr_flutter: ^4.1.0 riverpod_annotation: ^2.6.1 + shake_gesture: ^1.1.0 share_plus: ^10.0.2 shared_preferences: ^2.2.2 shimmer: ^3.0.0 From 3748535d9ae859b0ff5697ea78c4bd039b90977c Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:13:28 +0100 Subject: [PATCH 04/11] feat: move provider scope to main --- .../riverpod/root_provider_scope.dart | 26 ------------------- lib/main.dart | 11 +++++--- 2 files changed, 8 insertions(+), 29 deletions(-) delete mode 100644 lib/app/services/riverpod/root_provider_scope.dart diff --git a/lib/app/services/riverpod/root_provider_scope.dart b/lib/app/services/riverpod/root_provider_scope.dart deleted file mode 100644 index 538d2db7a..000000000 --- a/lib/app/services/riverpod/root_provider_scope.dart +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:talker_riverpod_logger/talker_riverpod_logger_observer.dart'; - -const _riverpodLoggerEnabled = false; - -class RiverpodRootProviderScope extends ConsumerWidget { - const RiverpodRootProviderScope({ - required this.child, - super.key, - }); - - final Widget child; - - @override - Widget build(BuildContext context, WidgetRef ref) { - return ProviderScope( - observers: [ - if (_riverpodLoggerEnabled) TalkerRiverpodObserver(), - ], - child: child, - ); - } -} diff --git a/lib/main.dart b/lib/main.dart index fcf81e038..645c01b89 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,11 +13,13 @@ import 'package:ion/app/features/wallet/components/coin_sync/coins_sync_wrapper. import 'package:ion/app/router/components/app_router_builder.dart'; import 'package:ion/app/router/components/modal_wrapper/sheet_scope.dart'; import 'package:ion/app/router/providers/go_router_provider.c.dart'; -import 'package:ion/app/services/riverpod/root_provider_scope.dart'; import 'package:ion/app/services/storage/secure_storage.c.dart'; import 'package:ion/app/theme/theme.dart'; import 'package:ion/generated/app_localizations.dart'; import 'package:ion/generated/assets.gen.dart'; +import 'package:talker_riverpod_logger/talker_riverpod_logger_observer.dart'; + +const _riverpodLoggerEnabled = false; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -25,8 +27,11 @@ void main() async { await dotenv.load(fileName: Assets.aApp); runApp( - const RiverpodRootProviderScope( - child: IONApp(), + ProviderScope( + observers: [ + if (_riverpodLoggerEnabled) TalkerRiverpodObserver(), + ], + child: const IONApp(), ), ); } From b6089a2944155f6cdc63ba8e1b4b697b0c97aa17 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:35:08 +0100 Subject: [PATCH 05/11] feat: self review --- lib/app/features/core/views/pages/error_modal.dart | 3 +-- .../lib/src/core/service_locator/network_service_locator.dart | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index f1de67f69..03b53dff2 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -19,8 +19,7 @@ class ErrorModal extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final showDebugInfo = - ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO) ?? false; + final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); final errorInfo = switch (error) { Object _ when showDebugInfo => error.toString(), diff --git a/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart b/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart index 6cc1212c7..90f3eea1c 100644 --- a/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart +++ b/packages/ion_identity_client/lib/src/core/service_locator/network_service_locator.dart @@ -72,9 +72,6 @@ mixin _Dio { } mixin _Interceptors { - final StringBuffer _logBuffer = StringBuffer(); - String get logs => _logBuffer.toString(); - Iterable interceptors({ required IONIdentityConfig config, }) { From 3d9672a89111844386ebcf7961fdbb86e7f30d9c Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 22:16:38 +0100 Subject: [PATCH 06/11] feat: show modal instead screen --- lib/app/features/debug/views/debug_page.dart | 85 +++++++++++-------- .../debug/views/debug_shake_gesture.dart | 45 ++++++---- .../utils/show_simple_bottom_sheet.dart | 2 + 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index 095e37168..039557dac 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -2,8 +2,10 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ion/app/extensions/extensions.dart'; import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart'; +import 'package:ion/app/router/components/navigation_app_bar/navigation_close_button.dart'; import 'package:ion/app/services/logger/logger.dart'; import 'package:talker_flutter/talker_flutter.dart'; @@ -14,49 +16,58 @@ class DebugPage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final featureFlags = ref.watch(featureFlagsProvider); - return Scaffold( - appBar: NavigationAppBar.screen( - title: const Text('🐞 Debug'), - ), - body: Padding( - padding: const EdgeInsets.all(16), - child: ListView( - children: [ - Card( - child: ListTile( - leading: const Icon(Icons.bug_report), - title: const Text('View Debug Logs'), - subtitle: const Text('Check application logs and diagnostics'), - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => TalkerScreen( - talker: Logger.talker, + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + NavigationAppBar.modal( + title: const Text('🐞 Debug'), + showBackButton: false, + actions: const [NavigationCloseButton()], + ), + Flexible( + child: Padding( + padding: const EdgeInsets.all(16), + child: ListView( + shrinkWrap: true, + children: [ + Card( + child: ListTile( + leading: const Icon(Icons.bug_report), + title: const Text('View Debug Logs'), + subtitle: const Text('Check application logs and diagnostics'), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => TalkerScreen( + talker: Logger.talker, + ), + ), ), ), ), - ), - ), - ExpansionTile( - title: const Text('Feature Flags'), - children: featureFlags.entries - .map( - (entry) => Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: ListTile( - title: Text(entry.key.key), - trailing: Icon( - entry.value ? Icons.check_circle : Icons.cancel, - color: entry.value ? Colors.green : Colors.red, + SizedBox(height: 16.0.s), + ExpansionTile( + title: const Text('Feature Flags'), + children: featureFlags.entries + .map( + (entry) => Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + title: Text(entry.key.key), + trailing: Icon( + entry.value ? Icons.check_circle : Icons.cancel, + color: entry.value ? Colors.green : Colors.red, + ), + ), ), - ), - ), - ) - .toList(), + ) + .toList(), + ), + ], ), - ], + ), ), - ), + ], ); } } diff --git a/lib/app/features/debug/views/debug_shake_gesture.dart b/lib/app/features/debug/views/debug_shake_gesture.dart index efbe6b4e5..35d815213 100644 --- a/lib/app/features/debug/views/debug_shake_gesture.dart +++ b/lib/app/features/debug/views/debug_shake_gesture.dart @@ -1,12 +1,14 @@ // SPDX-License-Identifier: ice License 1.0 import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ion/app/features/core/providers/env_provider.c.dart'; import 'package:ion/app/features/debug/views/debug_page.dart'; +import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart'; import 'package:shake_gesture/shake_gesture.dart'; -class DebugShakeGesture extends ConsumerWidget { +class DebugShakeGesture extends HookConsumerWidget { const DebugShakeGesture({ required this.child, super.key, @@ -18,21 +20,30 @@ class DebugShakeGesture extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); - return showDebugInfo - ? Navigator( - onGenerateRoute: (settings) => MaterialPageRoute( - builder: (context) => ShakeGesture( - onShake: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const DebugPage(), - ), - ); - }, - child: child, - ), - ), - ) - : child; + if (!showDebugInfo) return child; + + final isSheetOpen = useState(false); + + return Navigator( + onGenerateRoute: (settings) => MaterialPageRoute( + builder: (context) => ShakeGesture( + onShake: () { + if (isSheetOpen.value) return; + + isSheetOpen.value = true; + showSimpleBottomSheet( + context: context, + child: const DebugPage(), + onPopInvokedWithResult: (didPop, _) { + if (didPop) { + isSheetOpen.value = false; + } + }, + ); + }, + child: child, + ), + ), + ); } } diff --git a/lib/app/router/utils/show_simple_bottom_sheet.dart b/lib/app/router/utils/show_simple_bottom_sheet.dart index f2ac39432..68466424b 100644 --- a/lib/app/router/utils/show_simple_bottom_sheet.dart +++ b/lib/app/router/utils/show_simple_bottom_sheet.dart @@ -9,6 +9,7 @@ Future showSimpleBottomSheet({ required Widget child, bool useRootNavigator = true, bool isDismissible = true, + PopInvokedWithResultCallback? onPopInvokedWithResult, }) { return showModalBottomSheet( useRootNavigator: useRootNavigator, @@ -20,6 +21,7 @@ Future showSimpleBottomSheet({ builder: (context) { return PopScope( canPop: isDismissible, + onPopInvokedWithResult: onPopInvokedWithResult, child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, From 3cf1b182882565da3d8f90e9354be1205626576c Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Wed, 8 Jan 2025 23:24:47 +0100 Subject: [PATCH 07/11] feat: disable logs if not debug --- .../core/providers/dio_provider.c.dart | 12 ++--- .../providers/feature_flags_provider.c.dart | 11 +++-- .../core/providers/init_provider.c.dart | 11 +++-- .../core/views/pages/error_modal.dart | 5 ++- lib/app/features/debug/views/debug_page.dart | 24 +++++----- lib/app/services/logger/logger.dart | 44 ++++++++++++------- 6 files changed, 62 insertions(+), 45 deletions(-) diff --git a/lib/app/features/core/providers/dio_provider.c.dart b/lib/app/features/core/providers/dio_provider.c.dart index 6c6bedede..583bda8db 100644 --- a/lib/app/features/core/providers/dio_provider.c.dart +++ b/lib/app/features/core/providers/dio_provider.c.dart @@ -2,8 +2,6 @@ import 'package:dio/dio.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:ion/app/features/core/model/feature_flags.dart'; -import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/services/logger/logger.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -11,14 +9,12 @@ part 'dio_provider.c.g.dart'; @riverpod Dio dio(Ref ref) { - final logApp = ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logApp); - final dio = Dio(); - if (logApp) { - dio.interceptors.add( - Logger.talkerDioLogger, - ); + final logger = Logger.talkerDioLogger; + + if (logger != null) { + dio.interceptors.add(logger); } return dio; diff --git a/lib/app/features/core/providers/feature_flags_provider.c.dart b/lib/app/features/core/providers/feature_flags_provider.c.dart index 31ff0d35a..deaae9188 100644 --- a/lib/app/features/core/providers/feature_flags_provider.c.dart +++ b/lib/app/features/core/providers/feature_flags_provider.c.dart @@ -1,6 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 import 'package:ion/app/features/core/model/feature_flags.dart'; +import 'package:ion/app/features/core/providers/env_provider.c.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'feature_flags_provider.c.g.dart'; @@ -17,10 +18,12 @@ class FeatureFlags extends _$FeatureFlags { HideCreatorsWithoutPicture.hideCreatorsWithoutPicture: true, /// Log flags - LoggerFeatureFlag.logApp: true, - LoggerFeatureFlag.logRouters: false, - LoggerFeatureFlag.logNostrDart: true, - LoggerFeatureFlag.logIonIdentityClient: true, + if (ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO)) ...{ + LoggerFeatureFlag.logApp: true, + LoggerFeatureFlag.logRouters: false, + LoggerFeatureFlag.logNostrDart: true, + LoggerFeatureFlag.logIonIdentityClient: true, + }, }; } diff --git a/lib/app/features/core/providers/init_provider.c.dart b/lib/app/features/core/providers/init_provider.c.dart index 70eacd417..87d1f24c3 100644 --- a/lib/app/features/core/providers/init_provider.c.dart +++ b/lib/app/features/core/providers/init_provider.c.dart @@ -9,6 +9,7 @@ import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart'; import 'package:ion/app/features/core/providers/template_provider.c.dart'; import 'package:ion/app/features/core/providers/window_manager_provider.c.dart'; import 'package:ion/app/features/wallet/data/coins/domain/coin_initializer.c.dart'; +import 'package:ion/app/services/logger/logger.dart'; import 'package:ion/app/services/nostr/nostr.dart'; import 'package:ion/app/services/nostr/nostr_logger.dart'; import 'package:ion/app/services/storage/local_storage.c.dart'; @@ -18,11 +19,13 @@ part 'init_provider.c.g.dart'; @Riverpod(keepAlive: true) Future initApp(Ref ref) async { - final logNostrDart = ref.read(featureFlagsProvider.notifier).get(LoggerFeatureFlag.logNostrDart); + final featureFlagsNotifier = ref.read(featureFlagsProvider.notifier); + final logApp = featureFlagsNotifier.get(LoggerFeatureFlag.logApp); + final logNostrDart = featureFlagsNotifier.get(LoggerFeatureFlag.logNostrDart); - Nostr.initialize( - logNostrDart ? NostrLogger() : null, - ); + if (logApp) Logger.init(); + + Nostr.initialize(logNostrDart ? NostrLogger() : null); await Future.wait([ ref.read(windowManagerProvider.notifier).show(), diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index 03b53dff2..ad10f5832 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -10,10 +10,13 @@ import 'package:ion/app/components/screen_offset/screen_side_offset.dart'; import 'package:ion/app/exceptions/exceptions.dart'; import 'package:ion/app/extensions/extensions.dart'; import 'package:ion/app/features/core/providers/env_provider.c.dart'; +import 'package:ion/app/services/logger/logger.dart'; import 'package:ion/generated/assets.gen.dart'; class ErrorModal extends ConsumerWidget { - const ErrorModal({required this.error, super.key}); + ErrorModal({required this.error, super.key}) { + Logger.error(error); + } final Object error; diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index 039557dac..ab259ff8c 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -15,6 +15,7 @@ class DebugPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final featureFlags = ref.watch(featureFlagsProvider); + final talker = Logger.talker; return Column( mainAxisSize: MainAxisSize.min, @@ -30,21 +31,22 @@ class DebugPage extends ConsumerWidget { child: ListView( shrinkWrap: true, children: [ - Card( - child: ListTile( - leading: const Icon(Icons.bug_report), - title: const Text('View Debug Logs'), - subtitle: const Text('Check application logs and diagnostics'), - trailing: const Icon(Icons.chevron_right), - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => TalkerScreen( - talker: Logger.talker, + if (talker != null) + Card( + child: ListTile( + leading: const Icon(Icons.bug_report), + title: const Text('View Debug Logs'), + subtitle: const Text('Check application logs and diagnostics'), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => TalkerScreen( + talker: talker, + ), ), ), ), ), - ), SizedBox(height: 16.0.s), ExpansionTile( title: const Text('Feature Flags'), diff --git a/lib/app/services/logger/logger.dart b/lib/app/services/logger/logger.dart index 835d990a3..165125264 100644 --- a/lib/app/services/logger/logger.dart +++ b/lib/app/services/logger/logger.dart @@ -7,39 +7,49 @@ import 'package:talker_flutter/talker_flutter.dart'; class Logger { Logger._(); - static final Talker talker = TalkerFlutter.init(); - - static final talkerDioLogger = TalkerDioLogger( - talker: talker, - settings: TalkerDioLoggerSettings( - printRequestHeaders: true, - printResponseHeaders: true, - requestPen: AnsiPen()..cyan(), - responsePen: AnsiPen()..green(), - errorPen: AnsiPen()..red(), - ), - ); + static Talker? _talker; + + static void init() { + _talker = TalkerFlutter.init(); + } + + static Talker? get talker => _talker; + + static TalkerDioLogger? get talkerDioLogger => TalkerDioLogger( + talker: talker, + settings: TalkerDioLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + requestPen: AnsiPen()..cyan(), + responsePen: AnsiPen()..green(), + errorPen: AnsiPen()..red(), + ), + ); static void log( String message, { Object? error, StackTrace? stackTrace, }) { - talker.log(message); + _talker?.log(message); if (error != null) { - talker.error(error, stackTrace); + _talker?.error(error, stackTrace); } } - static void info(String message) => talker.info(message); + static void info(String message) { + _talker?.info(message); + } - static void warning(String message) => talker.warning(message); + static void warning(String message) { + _talker?.warning(message); + } static void error( Object error, { StackTrace? stackTrace, }) { - talker.error(error, stackTrace); + _talker?.error(error, stackTrace); } } From ef670c66b32b77f5168fc56044f847c99d26cee8 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:14:10 +0100 Subject: [PATCH 08/11] fix: change read to watch for envProvider --- .../chat/providers/conversation_message_actions_provider.c.dart | 2 +- .../providers/conversation_message_management_provider.c.dart | 2 +- lib/app/features/config/providers/config_provider.c.dart | 2 +- .../features/config/providers/force_update_util_provider.c.dart | 2 +- lib/app/features/core/providers/feature_flags_provider.c.dart | 2 +- lib/app/features/core/views/pages/error_modal.dart | 2 +- lib/app/features/debug/views/debug_shake_gesture.dart | 2 +- lib/app/services/ion_identity/ion_identity_provider.c.dart | 2 +- lib/app/services/media_service/banuba_service.c.dart | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart index 2577de1fb..f4062f696 100644 --- a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart @@ -37,7 +37,7 @@ Future> conversationMessageActionsService return ConversationMessageActionsService( eventSigner: eventSigner, databaseService: databaseService, - env: ref.read(envProvider.notifier), + env: ref.watch(envProvider.notifier), userPubkey: await ref.watch(currentPubkeySelectorProvider.future), sealService: ref.watch(ionConnectSealServiceProvider), nostrNotifier: ref.watch(nostrNotifierProvider.notifier), diff --git a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart index 67c290f34..006a09673 100644 --- a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart @@ -36,7 +36,7 @@ Future> conversationMessageManagementS return ConversationMessageManagementService( eventSigner: eventSigner, - env: ref.read(envProvider.notifier), + env: ref.watch(envProvider.notifier), fileCacheService: ref.watch(fileCacheServiceProvider), sealService: ref.watch(ionConnectSealServiceProvider), compressionService: ref.watch(compressServiceProvider), diff --git a/lib/app/features/config/providers/config_provider.c.dart b/lib/app/features/config/providers/config_provider.c.dart index 6a960bb88..6c9d613d5 100644 --- a/lib/app/features/config/providers/config_provider.c.dart +++ b/lib/app/features/config/providers/config_provider.c.dart @@ -47,7 +47,7 @@ Future configForPlatform(Ref ref) async { } } - final baseUrl = ref.read(envProvider.notifier).get(EnvVariable.ION_ORIGIN); + final baseUrl = ref.watch(envProvider.notifier).get(EnvVariable.ION_ORIGIN); final configName = getPlatformConfigName(); final path = '$baseUrl/v1/config/$configName'; diff --git a/lib/app/features/config/providers/force_update_util_provider.c.dart b/lib/app/features/config/providers/force_update_util_provider.c.dart index d55743f2b..db44e01b9 100644 --- a/lib/app/features/config/providers/force_update_util_provider.c.dart +++ b/lib/app/features/config/providers/force_update_util_provider.c.dart @@ -56,5 +56,5 @@ class ForceUpdateUtil { @riverpod ForceUpdateUtil forceUpdateService(Ref ref) { - return ForceUpdateUtil(ref.read(envProvider.notifier)); + return ForceUpdateUtil(ref.watch(envProvider.notifier)); } diff --git a/lib/app/features/core/providers/feature_flags_provider.c.dart b/lib/app/features/core/providers/feature_flags_provider.c.dart index deaae9188..56ae4a835 100644 --- a/lib/app/features/core/providers/feature_flags_provider.c.dart +++ b/lib/app/features/core/providers/feature_flags_provider.c.dart @@ -18,7 +18,7 @@ class FeatureFlags extends _$FeatureFlags { HideCreatorsWithoutPicture.hideCreatorsWithoutPicture: true, /// Log flags - if (ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO)) ...{ + if (ref.watch(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO)) ...{ LoggerFeatureFlag.logApp: true, LoggerFeatureFlag.logRouters: false, LoggerFeatureFlag.logNostrDart: true, diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index ad10f5832..66bff2f49 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -22,7 +22,7 @@ class ErrorModal extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); + final showDebugInfo = ref.watch(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); final errorInfo = switch (error) { Object _ when showDebugInfo => error.toString(), diff --git a/lib/app/features/debug/views/debug_shake_gesture.dart b/lib/app/features/debug/views/debug_shake_gesture.dart index 35d815213..b09ad0e9b 100644 --- a/lib/app/features/debug/views/debug_shake_gesture.dart +++ b/lib/app/features/debug/views/debug_shake_gesture.dart @@ -18,7 +18,7 @@ class DebugShakeGesture extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final showDebugInfo = ref.read(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); + final showDebugInfo = ref.watch(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO); if (!showDebugInfo) return child; diff --git a/lib/app/services/ion_identity/ion_identity_provider.c.dart b/lib/app/services/ion_identity/ion_identity_provider.c.dart index 18ae07e4d..aa2074fc0 100644 --- a/lib/app/services/ion_identity/ion_identity_provider.c.dart +++ b/lib/app/services/ion_identity/ion_identity_provider.c.dart @@ -14,7 +14,7 @@ part 'ion_identity_provider.c.g.dart'; @Riverpod(keepAlive: true) Future> ionIdentity(Ref ref) async { - final env = ref.read(envProvider.notifier); + final env = ref.watch(envProvider.notifier); final appId = env.get( Platform.isAndroid ? EnvVariable.ION_ANDROID_APP_ID : EnvVariable.ION_IOS_APP_ID, diff --git a/lib/app/services/media_service/banuba_service.c.dart b/lib/app/services/media_service/banuba_service.c.dart index 97fa8d1c5..73d25b327 100644 --- a/lib/app/services/media_service/banuba_service.c.dart +++ b/lib/app/services/media_service/banuba_service.c.dart @@ -84,7 +84,7 @@ class BanubaService { @riverpod BanubaService banubaService(Ref ref) { - return BanubaService(ref.read(envProvider.notifier)); + return BanubaService(ref.watch(envProvider.notifier)); } @riverpod From a2410dd61fa5ec1edc61941d2b99da7ebec9181e Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:15:14 +0100 Subject: [PATCH 09/11] fix: change read to watch for featureFlagProvider --- lib/app/features/feed/views/pages/feed_page/feed_page.dart | 2 +- .../views/pages/wallet_page/components/loaders/grid_loader.dart | 2 +- .../pages/wallet_page/components/nfts/nfts_tab_footer.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/app/features/feed/views/pages/feed_page/feed_page.dart b/lib/app/features/feed/views/pages/feed_page/feed_page.dart index dc825f62c..5b9bf01c1 100644 --- a/lib/app/features/feed/views/pages/feed_page/feed_page.dart +++ b/lib/app/features/feed/views/pages/feed_page/feed_page.dart @@ -35,7 +35,7 @@ class FeedPage extends HookConsumerWidget { .select((state) => (state?.hasMore).falseOrValue), ); final showTrendingVideos = - ref.read(featureFlagsProvider.notifier).get(FeedFeatureFlag.showTrendingVideo); + ref.watch(featureFlagsProvider.notifier).get(FeedFeatureFlag.showTrendingVideo); useScrollTopOnTabPress(context, scrollController: scrollController); diff --git a/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart b/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart index 5457299c4..3e6fc28d0 100644 --- a/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart +++ b/lib/app/features/wallet/views/pages/wallet_page/components/loaders/grid_loader.dart @@ -16,7 +16,7 @@ class GridLoader extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final buyNftFeatureEnabled = - ref.read(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); + ref.watch(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); final width = (MediaQuery.sizeOf(context).width - ScreenSideOffset.defaultSmallMargin * 2 - 12.0.s) / 2; diff --git a/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart b/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart index 00b739fba..467c251f1 100644 --- a/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart +++ b/lib/app/features/wallet/views/pages/wallet_page/components/nfts/nfts_tab_footer.dart @@ -21,7 +21,7 @@ class NftsTabFooter extends ConsumerWidget { final searchVisibleProvider = walletSearchVisibilityProvider(tabType); final isSearchVisible = ref.watch(searchVisibleProvider); final buyNftFeatureEnabled = - ref.read(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); + ref.watch(featureFlagsProvider.notifier).get(WalletFeatureFlag.buyNftEnabled); return SliverToBoxAdapter( child: buyNftFeatureEnabled && !isSearchVisible From 2275ef2aed25f0174a83e66e3ffb9abdeade2152 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:38:22 +0100 Subject: [PATCH 10/11] refactor: change Logger to singleton --- .../onboarding_complete_notifier.c.dart | 2 +- .../message_item_wrapper.dart | 2 +- .../components/more_content_view.dart | 2 +- ...nversation_message_actions_provider.c.dart | 14 +++++------ ...rsation_message_management_provider.c.dart | 22 ++++++++--------- .../core/providers/dio_provider.c.dart | 2 +- .../core/providers/init_provider.c.dart | 2 +- .../core/views/pages/error_modal.dart | 2 +- lib/app/features/debug/views/debug_page.dart | 2 +- .../create_post_modal/hooks/use_has_poll.dart | 2 +- .../suggestions_notifier_provider.c.dart | 2 +- .../gallery/providers/camera_provider.c.dart | 16 ++++++------- .../gallery/providers/gallery_provider.c.dart | 2 +- .../nostr/providers/nostr_notifier.c.dart | 2 +- .../user/providers/user_relays_manager.c.dart | 2 +- .../providers/go_router_provider.c.dart | 2 +- .../audio_wave_playback_service.c.dart | 4 ++-- lib/app/services/browser/browser.dart | 2 +- .../compressor/compress_service.c.dart | 18 +++++++------- .../ion_identity/ion_identity_provider.c.dart | 2 +- lib/app/services/logger/logger.dart | 24 ++++++++++++------- .../services/media_service/album_service.dart | 2 +- .../media_service/banuba_service.c.dart | 6 ++--- .../media_service/media_service.c.dart | 4 ++-- lib/app/services/nostr/nostr_logger.dart | 8 +++---- lib/app/utils/retry.dart | 4 ++-- 26 files changed, 79 insertions(+), 73 deletions(-) diff --git a/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart b/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart index 08f8d044c..18c345385 100644 --- a/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart +++ b/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart @@ -205,7 +205,7 @@ class OnboardingCompleteNotifier extends _$OnboardingCompleteNotifier { } } catch (error, stackTrace) { // intentionally ignore upload avatar exceptions - Logger.log('Upload avatar exception', error: error, stackTrace: stackTrace); + Logger().log('Upload avatar exception', error: error, stackTrace: stackTrace); } return null; } diff --git a/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart b/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart index 8ddee2b7d..3cd792b4b 100644 --- a/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart +++ b/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart @@ -41,7 +41,7 @@ class MessageItemWrapper extends HookWidget { ), ); } catch (e, st) { - Logger.log('Error showing message reaction dialog:', error: e, stackTrace: st); + Logger().log('Error showing message reaction dialog:', error: e, stackTrace: st); } }, [messageItemKey, isMe], diff --git a/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart b/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart index 52b2fb0d8..a76c11666 100644 --- a/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart +++ b/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart @@ -54,7 +54,7 @@ class MoreContentView extends ConsumerWidget { ).push(context); //TODO: use contactId to share profile - Logger.log(contactId ?? 'No contact selected'); + Logger().log(contactId ?? 'No contact selected'); ref.read(messagingBottomBarActiveStateProvider.notifier).setText(); }, diff --git a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart index f4062f696..045cb15b4 100644 --- a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart @@ -87,7 +87,7 @@ class ConversationMessageActionsService { ['encrypted'], ]; - Logger.log('Encoded rumor $encodedRumor'); + Logger().log('Encoded rumor $encodedRumor'); final encryptedRumor = await Nip44.encryptMessage( encodedRumor, @@ -95,7 +95,7 @@ class ConversationMessageActionsService { receiverPubkey, ); - Logger.log('Encrypted rumor $encryptedRumor'); + Logger().log('Encrypted rumor $encryptedRumor'); final id = EventMessage.calculateEventId( tags: tags, @@ -115,7 +115,7 @@ class ConversationMessageActionsService { sig: null, ); - Logger.log('Bookmark message $bookmarkMessage'); + Logger().log('Bookmark message $bookmarkMessage'); await nostrNotifier.sendEvent(bookmarkMessage, cache: false); } @@ -211,7 +211,7 @@ class ConversationMessageActionsService { sig: await signer.sign(message: id), ); - Logger.log('Event message $eventMessage'); + Logger().log('Event message $eventMessage'); final seal = await sealService.createSeal( eventMessage, @@ -219,7 +219,7 @@ class ConversationMessageActionsService { receiverPubkey, ); - Logger.log('Seal message $seal'); + Logger().log('Seal message $seal'); final expirationTag = EntityExpiration( value: DateTime.now().add( @@ -235,11 +235,11 @@ class ConversationMessageActionsService { expirationTag: expirationTag, ); - Logger.log('Wrap message $wrap'); + Logger().log('Wrap message $wrap'); final result = await nostrNotifier.sendEvent(wrap, cache: false); - Logger.log('Sent message $result'); + Logger().log('Sent message $result'); return result; } diff --git a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart index 006a09673..4a4967b70 100644 --- a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart @@ -101,7 +101,7 @@ class ConversationMessageManagementService { alt: FileAlt.message, ); - Logger.log( + Logger().log( 'Uploaded media file: ${uploadResult.fileMetadata.url}, ${uploadResult.fileMetadata.mimeType} ${uploadResult.fileMetadata.size}', ); @@ -147,7 +147,7 @@ class ConversationMessageManagementService { final decryptedDecompressedFiles = []; for (final attachment in privateDirectMessageEntity.data.media.values) { - Logger.log('Attachment: $attachment'); + Logger().log('Attachment: $attachment'); if (attachment.encryptionKey != null && attachment.encryptionNonce != null && attachment.encryptionMac != null) { @@ -157,7 +157,7 @@ class ConversationMessageManagementService { final file = await fileCacheService.getFile(attachment.url); - Logger.log( + Logger().log( 'Downloaded encrypted media file: ${file.path}, ${attachment.mimeType} ${file.lengthSync()}', ); @@ -184,7 +184,7 @@ class ConversationMessageManagementService { fileExtension: attachment.mimeType.split('/').last, ); - Logger.log( + Logger().log( 'Decrypted media file: ${decryptedFile.path}, ${attachment.mimeType} ${decryptedFile.lengthSync()}', ); @@ -238,7 +238,7 @@ class ConversationMessageManagementService { sig: null, ); - Logger.log('Event message $eventMessage'); + Logger().log('Event message $eventMessage'); final seal = await sealService.createSeal( eventMessage, @@ -246,7 +246,7 @@ class ConversationMessageManagementService { receiverPubkey, ); - Logger.log('Seal message $seal'); + Logger().log('Seal message $seal'); final wrap = await wrapService.createWrap( seal, @@ -255,11 +255,11 @@ class ConversationMessageManagementService { PrivateDirectMessageEntity.kind, ); - Logger.log('Wrap message $wrap'); + Logger().log('Wrap message $wrap'); final result = await nostrNotifier.sendEvent(wrap, cache: false); - Logger.log('Sent message $result'); + Logger().log('Sent message $result'); return result; } @@ -273,7 +273,7 @@ class ConversationMessageManagementService { mediaFiles.map( (mediaFile) async { final size = File(mediaFile.path).lengthSync(); - Logger.log( + Logger().log( 'Original media file: ${mediaFile.path}, ${mediaFile.mimeType} $size', ); @@ -298,7 +298,7 @@ class ConversationMessageManagementService { }; final compressedSize = File(compressedMediaFile.path).lengthSync(); - Logger.log( + Logger().log( 'Compressed media file: ${compressedMediaFile.path}, ${compressedMediaFile.mimeType} $compressedSize', ); @@ -342,7 +342,7 @@ class ConversationMessageManagementService { mimeType: compressedMediaFile.mimeType, ); - Logger.log( + Logger().log( 'Encrypted media file ${compressedEncryptedMediaFile.mimeType} ${compressedEncryptedFile.lengthSync()}', ); diff --git a/lib/app/features/core/providers/dio_provider.c.dart b/lib/app/features/core/providers/dio_provider.c.dart index 583bda8db..f0aab814a 100644 --- a/lib/app/features/core/providers/dio_provider.c.dart +++ b/lib/app/features/core/providers/dio_provider.c.dart @@ -11,7 +11,7 @@ part 'dio_provider.c.g.dart'; Dio dio(Ref ref) { final dio = Dio(); - final logger = Logger.talkerDioLogger; + final logger = Logger().talkerDioLogger; if (logger != null) { dio.interceptors.add(logger); diff --git a/lib/app/features/core/providers/init_provider.c.dart b/lib/app/features/core/providers/init_provider.c.dart index 87d1f24c3..d2dceae71 100644 --- a/lib/app/features/core/providers/init_provider.c.dart +++ b/lib/app/features/core/providers/init_provider.c.dart @@ -23,7 +23,7 @@ Future initApp(Ref ref) async { final logApp = featureFlagsNotifier.get(LoggerFeatureFlag.logApp); final logNostrDart = featureFlagsNotifier.get(LoggerFeatureFlag.logNostrDart); - if (logApp) Logger.init(); + if (logApp) Logger().init(); Nostr.initialize(logNostrDart ? NostrLogger() : null); diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index 66bff2f49..55978fed7 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -15,7 +15,7 @@ import 'package:ion/generated/assets.gen.dart'; class ErrorModal extends ConsumerWidget { ErrorModal({required this.error, super.key}) { - Logger.error(error); + Logger().error(error); } final Object error; diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index ab259ff8c..2f620342d 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -15,7 +15,7 @@ class DebugPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final featureFlags = ref.watch(featureFlagsProvider); - final talker = Logger.talker; + final talker = Logger().talker; return Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart b/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart index 4a92a9438..9356ac666 100644 --- a/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart +++ b/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart @@ -58,7 +58,7 @@ bool _containsPollKey(dynamic customData) { try { parsedData = jsonDecode(customData) as Map?; } catch (e) { - Logger.log('Failed to parse custom data: $e'); + Logger().log('Failed to parse custom data: $e'); } } diff --git a/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart b/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart index 9d659ce2f..43b5c4486 100644 --- a/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart +++ b/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart @@ -27,7 +27,7 @@ class SuggestionsNotifier extends _$SuggestionsNotifier { newSuggestions = await ref.read(mentionSuggestionsProvider(query).future); } } catch (error) { - Logger.log('Error fetching suggestions: $error'); + Logger().log('Error fetching suggestions: $error'); } state = newSuggestions; diff --git a/lib/app/features/gallery/providers/camera_provider.c.dart b/lib/app/features/gallery/providers/camera_provider.c.dart index 6ee1d7ad1..32f70bdf3 100644 --- a/lib/app/features/gallery/providers/camera_provider.c.dart +++ b/lib/app/features/gallery/providers/camera_provider.c.dart @@ -66,7 +66,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final initialCamera = _backCamera ?? _frontCamera; if (initialCamera == null) { - Logger.log('Camera not found'); + Logger().log('Camera not found'); state = const CameraState.error(message: 'Camera not found'); return; } @@ -74,7 +74,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final controller = await _createCameraController(initialCamera); state = CameraState.ready(controller: controller); } catch (e) { - Logger.log('Camera initialization error: $e'); + Logger().log('Camera initialization error: $e'); state = CameraState.error(message: 'Camera initialization error: $e'); } } @@ -90,7 +90,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { _cameraController?.addListener(_onCameraControllerUpdate); return _cameraController!; } catch (e) { - Logger.log('Camera initialization error: $e'); + Logger().log('Camera initialization error: $e'); await _disposeCamera(); throw Exception('Camera initialization error: $e'); } @@ -154,7 +154,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: mode == FlashMode.torch, ); } catch (e) { - Logger.log('Error setting flash mode', error: e); + Logger().log('Error setting flash mode', error: e); state = CameraState.error(message: 'Error setting flash mode: $e'); } }, @@ -174,7 +174,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: !isFlashOn, ); } catch (e) { - Logger.log('Error toggling flash mode', error: e); + Logger().log('Error toggling flash mode', error: e); state = CameraState.error(message: 'Error toggling flash mode: $e'); } }, @@ -189,7 +189,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final picture = await _cameraController!.takePicture(); return picture; } catch (e) { - Logger.log('Error taking picture', error: e); + Logger().log('Error taking picture', error: e); return null; } } @@ -206,7 +206,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: isFlashOn, ); } catch (e) { - Logger.log('Error starting video recording', error: e); + Logger().log('Error starting video recording', error: e); state = CameraState.error(message: 'Error starting video recording: $e'); } } @@ -240,7 +240,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { return videoFile; } catch (e) { - Logger.log('Error stopping video recording', error: e); + Logger().log('Error stopping video recording', error: e); state = CameraState.error(message: 'Error stopping video recording: $e'); return null; } diff --git a/lib/app/features/gallery/providers/gallery_provider.c.dart b/lib/app/features/gallery/providers/gallery_provider.c.dart index 45a6a0d64..fab286d49 100644 --- a/lib/app/features/gallery/providers/gallery_provider.c.dart +++ b/lib/app/features/gallery/providers/gallery_provider.c.dart @@ -53,7 +53,7 @@ class GalleryNotifier extends _$GalleryNotifier { final hasPermission = ref.read(hasPermissionProvider(Permission.photos)); if (!hasPermission) { - Logger.log('Photos Permission denied'); + Logger().log('Photos Permission denied'); return GalleryState( mediaData: [], currentPage: 0, diff --git a/lib/app/features/nostr/providers/nostr_notifier.c.dart b/lib/app/features/nostr/providers/nostr_notifier.c.dart index d5d4c4f39..6f48ba542 100644 --- a/lib/app/features/nostr/providers/nostr_notifier.c.dart +++ b/lib/app/features/nostr/providers/nostr_notifier.c.dart @@ -173,7 +173,7 @@ class NostrNotifier extends _$NostrNotifier { try { yield _parseAndCache(event); } catch (error, stackTrace) { - Logger.log('Failed to process event ${event.id}', error: error, stackTrace: stackTrace); + Logger().log('Failed to process event ${event.id}', error: error, stackTrace: stackTrace); } } } diff --git a/lib/app/features/user/providers/user_relays_manager.c.dart b/lib/app/features/user/providers/user_relays_manager.c.dart index 6bc63c640..bd1a50f1f 100644 --- a/lib/app/features/user/providers/user_relays_manager.c.dart +++ b/lib/app/features/user/providers/user_relays_manager.c.dart @@ -91,7 +91,7 @@ class UserRelaysManager extends _$UserRelaysManager { try { return await ionIdentity.users.details(userId: pubkey); } catch (error, stackTrace) { - Logger.log('Error fetching user relays', error: error, stackTrace: stackTrace); + Logger().log('Error fetching user relays', error: error, stackTrace: stackTrace); } }), ); diff --git a/lib/app/router/providers/go_router_provider.c.dart b/lib/app/router/providers/go_router_provider.c.dart index 8cec5edf8..3405526d5 100644 --- a/lib/app/router/providers/go_router_provider.c.dart +++ b/lib/app/router/providers/go_router_provider.c.dart @@ -36,7 +36,7 @@ GoRouter goRouter(Ref ref) { final isInitError = initState.hasError; if (isInitError) { - Logger.log('Init error', error: initState.error); + Logger().log('Init error', error: initState.error); return ErrorRoute().location; } diff --git a/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart b/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart index 8fb6ffbeb..3eebff484 100644 --- a/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart +++ b/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart @@ -33,7 +33,7 @@ class AudioWavePlaybackService { await preparePlayer(savedFilePath, audioPlaybackController, playerWaveStyle); } } catch (e, s) { - Logger.log('Error initializing player', error: e, stackTrace: s); + Logger().log('Error initializing player', error: e, stackTrace: s); } } @@ -48,7 +48,7 @@ class AudioWavePlaybackService { noOfSamples: playerWaveStyle.getSamplesForWidth(158.0.s), ); } catch (e, s) { - Logger.log('Error preparing player', error: e, stackTrace: s); + Logger().log('Error preparing player', error: e, stackTrace: s); } } diff --git a/lib/app/services/browser/browser.dart b/lib/app/services/browser/browser.dart index b7fc28233..6a47ad6d7 100644 --- a/lib/app/services/browser/browser.dart +++ b/lib/app/services/browser/browser.dart @@ -15,7 +15,7 @@ Future openUrl( return false; } } catch (error) { - Logger.log('Could not launch $url', error: error); + Logger().log('Could not launch $url', error: error); return false; } } diff --git a/lib/app/services/compressor/compress_service.c.dart b/lib/app/services/compressor/compress_service.c.dart index f8f49192d..0c2a65709 100644 --- a/lib/app/services/compressor/compress_service.c.dart +++ b/lib/app/services/compressor/compress_service.c.dart @@ -84,13 +84,13 @@ class CompressionService { final match = RegExp(r'Stream.*Video:.* (\d+)x(\d+)').firstMatch(logs); if (match == null) { - Logger.log('Failed to compress video. Dimension not found. Logs: $logs'); + Logger().log('Failed to compress video. Dimension not found. Logs: $logs'); throw CompressVideoException('no-dim'); } if (!ReturnCode.isSuccess(returnCode)) { final stackTrace = await session.getFailStackTrace(); - Logger.log('Failed to compress video. Logs: $logs, StackTrace: $stackTrace'); + Logger().log('Failed to compress video. Logs: $logs, StackTrace: $stackTrace'); throw CompressVideoException(returnCode); } @@ -101,7 +101,7 @@ class CompressionService { height: int.parse(match.group(2)!), ); } catch (error, stackTrace) { - Logger.log('Error during video compression!', error: error, stackTrace: stackTrace); + Logger().log('Error during video compression!', error: error, stackTrace: stackTrace); rethrow; } } @@ -144,7 +144,7 @@ class CompressionService { height: outputDimension.height, ); } catch (error, stackTrace) { - Logger.log('Error during image compression!', error: error, stackTrace: stackTrace); + Logger().log('Error during image compression!', error: error, stackTrace: stackTrace); rethrow; } } @@ -169,7 +169,7 @@ class CompressionService { } final logs = await session.getAllLogsAsString(); final stackTrace = await session.getFailStackTrace(); - Logger.log('Failed to convert audio to opus. Logs: $logs, StackTrace: $stackTrace'); + Logger().log('Failed to convert audio to opus. Logs: $logs, StackTrace: $stackTrace'); throw CompressAudioException(); }); } @@ -195,7 +195,7 @@ class CompressionService { } final logs = await session.getAllLogsAsString(); final stackTrace = await session.getFailStackTrace(); - Logger.log('Failed to convert audio to wav. Logs: $logs, StackTrace: $stackTrace'); + Logger().log('Failed to convert audio to wav. Logs: $logs, StackTrace: $stackTrace'); throw CompressAudioToWavException(); }); } @@ -246,7 +246,7 @@ class CompressionService { return compressedImage; } catch (error, stackTrace) { - Logger.log('Error during thumbnail extraction!', error: error, stackTrace: stackTrace); + Logger().log('Error during thumbnail extraction!', error: error, stackTrace: stackTrace); rethrow; } } @@ -271,7 +271,7 @@ class CompressionService { return _saveBytesIntoFile(bytes: compressedData, extension: 'br'); } catch (error, stackTrace) { - Logger.log('Error during Brotli compression!', error: error, stackTrace: stackTrace); + Logger().log('Error during Brotli compression!', error: error, stackTrace: stackTrace); throw CompressWithBrotliException(); } } @@ -287,7 +287,7 @@ class CompressionService { ); return _saveBytesIntoFile(bytes: decompressedData, extension: outputExtension); } catch (error, stackTrace) { - Logger.log('Error during Brotli decompression!', error: error, stackTrace: stackTrace); + Logger().log('Error during Brotli decompression!', error: error, stackTrace: stackTrace); throw DecompressBrotliException(); } } diff --git a/lib/app/services/ion_identity/ion_identity_provider.c.dart b/lib/app/services/ion_identity/ion_identity_provider.c.dart index aa2074fc0..d13b41237 100644 --- a/lib/app/services/ion_identity/ion_identity_provider.c.dart +++ b/lib/app/services/ion_identity/ion_identity_provider.c.dart @@ -26,7 +26,7 @@ Future> ionIdentity(Ref ref) async { final config = IONIdentityConfig( appId: appId, origin: env.get(EnvVariable.ION_ORIGIN), - logger: logIonIdentityClient ? Logger.talkerDioLogger : null, + logger: logIonIdentityClient ? Logger().talkerDioLogger : null, ); final ionClient = IONIdentity.createDefault(config: config); diff --git a/lib/app/services/logger/logger.dart b/lib/app/services/logger/logger.dart index 165125264..44806e691 100644 --- a/lib/app/services/logger/logger.dart +++ b/lib/app/services/logger/logger.dart @@ -5,17 +5,23 @@ import 'package:talker_dio_logger/talker_dio_logger_settings.dart'; import 'package:talker_flutter/talker_flutter.dart'; class Logger { + factory Logger() { + return _instance; + } + Logger._(); - static Talker? _talker; + static final Logger _instance = Logger._(); + + Talker? _talker; - static void init() { + Talker? get talker => _talker; + + void init() { _talker = TalkerFlutter.init(); } - static Talker? get talker => _talker; - - static TalkerDioLogger? get talkerDioLogger => TalkerDioLogger( + TalkerDioLogger? get talkerDioLogger => TalkerDioLogger( talker: talker, settings: TalkerDioLoggerSettings( printRequestHeaders: true, @@ -26,7 +32,7 @@ class Logger { ), ); - static void log( + void log( String message, { Object? error, StackTrace? stackTrace, @@ -38,15 +44,15 @@ class Logger { } } - static void info(String message) { + void info(String message) { _talker?.info(message); } - static void warning(String message) { + void warning(String message) { _talker?.warning(message); } - static void error( + void error( Object error, { StackTrace? stackTrace, }) { diff --git a/lib/app/services/media_service/album_service.dart b/lib/app/services/media_service/album_service.dart index 49f58b88e..cb201ccf3 100644 --- a/lib/app/services/media_service/album_service.dart +++ b/lib/app/services/media_service/album_service.dart @@ -49,7 +49,7 @@ class AlbumService { }) async { final assetPath = _albumsCache[albumId]; if (assetPath == null) { - Logger.log('Album not found in cache: $albumId'); + Logger().log('Album not found in cache: $albumId'); return []; } diff --git a/lib/app/services/media_service/banuba_service.c.dart b/lib/app/services/media_service/banuba_service.c.dart index 73d25b327..feae6c2a8 100644 --- a/lib/app/services/media_service/banuba_service.c.dart +++ b/lib/app/services/media_service/banuba_service.c.dart @@ -60,7 +60,7 @@ class BanubaService { } return filePath; } on PlatformException catch (e) { - Logger.log( + Logger().log( 'Start Photo Editor error', error: e, stackTrace: StackTrace.current, @@ -92,7 +92,7 @@ Future editMedia(Ref ref, MediaFile mediaFile) async { final filePath = await ref.read(assetFilePathProvider(mediaFile.path).future); if (filePath == null) { - Logger.log( + Logger().log( 'File path or mime type is null', error: mediaFile, stackTrace: StackTrace.current, @@ -101,7 +101,7 @@ Future editMedia(Ref ref, MediaFile mediaFile) async { } if (mediaFile.mimeType == null) { - Logger.log( + Logger().log( 'Mime type is null', error: mediaFile, stackTrace: StackTrace.current, diff --git a/lib/app/services/media_service/media_service.c.dart b/lib/app/services/media_service/media_service.c.dart index 454831f51..ff0c92b9c 100644 --- a/lib/app/services/media_service/media_service.c.dart +++ b/lib/app/services/media_service/media_service.c.dart @@ -88,7 +88,7 @@ class MediaService { return mediaFiles; } catch (e) { - Logger.log('Error fetching gallery images: $e'); + Logger().log('Error fetching gallery images: $e'); return []; } } @@ -198,7 +198,7 @@ class MediaService { } return null; } catch (e, st) { - Logger.log('Error capturing widget as image:', error: e, stackTrace: st); + Logger().log('Error capturing widget as image:', error: e, stackTrace: st); return null; } } diff --git a/lib/app/services/nostr/nostr_logger.dart b/lib/app/services/nostr/nostr_logger.dart index d17f2acc0..81654d689 100644 --- a/lib/app/services/nostr/nostr_logger.dart +++ b/lib/app/services/nostr/nostr_logger.dart @@ -8,19 +8,19 @@ class NostrLogger implements NostrDartLogger { @override void info(String message, [Object? error, StackTrace? stackTrace]) { - Logger.info('$_prefix $message'); + Logger().info('$_prefix $message'); if (error != null) { - Logger.error('$_prefix $error', stackTrace: stackTrace); + Logger().error('$_prefix $error', stackTrace: stackTrace); } } @override void warning(String message, [Object? error, StackTrace? stackTrace]) { - Logger.warning('$_prefix $message'); + Logger().warning('$_prefix $message'); if (error != null) { - Logger.error('$_prefix $error', stackTrace: stackTrace); + Logger().error('$_prefix $error', stackTrace: stackTrace); } } } diff --git a/lib/app/utils/retry.dart b/lib/app/utils/retry.dart index e4d238bdd..679a3498b 100644 --- a/lib/app/utils/retry.dart +++ b/lib/app/utils/retry.dart @@ -59,7 +59,7 @@ Stream withRetryStream( rethrow; } - Logger.log(e.toString()); + Logger().log(e.toString()); attempt++; if (attempt >= maxRetries) { rethrow; @@ -73,7 +73,7 @@ Stream withRetryStream( maxJitter: maxJitter, ); - Logger.log('Retry #$attempt after ${delay.inMilliseconds}ms...'); + Logger().log('Retry #$attempt after ${delay.inMilliseconds}ms...'); await Future.delayed(delay); } onRetry?.call(); From 02055024a11c77311c0b00f01fcd33e0c99bfb81 Mon Sep 17 00:00:00 2001 From: ion-endymion <188437551+ice-endymion@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:10:24 +0100 Subject: [PATCH 11/11] Revert "refactor: change Logger to singleton" This reverts commit 2275ef2aed25f0174a83e66e3ffb9abdeade2152. --- .../onboarding_complete_notifier.c.dart | 2 +- .../message_item_wrapper.dart | 2 +- .../components/more_content_view.dart | 2 +- ...nversation_message_actions_provider.c.dart | 14 +++++------ ...rsation_message_management_provider.c.dart | 22 ++++++++--------- .../core/providers/dio_provider.c.dart | 2 +- .../core/providers/init_provider.c.dart | 2 +- .../core/views/pages/error_modal.dart | 2 +- lib/app/features/debug/views/debug_page.dart | 2 +- .../create_post_modal/hooks/use_has_poll.dart | 2 +- .../suggestions_notifier_provider.c.dart | 2 +- .../gallery/providers/camera_provider.c.dart | 16 ++++++------- .../gallery/providers/gallery_provider.c.dart | 2 +- .../nostr/providers/nostr_notifier.c.dart | 2 +- .../user/providers/user_relays_manager.c.dart | 2 +- .../providers/go_router_provider.c.dart | 2 +- .../audio_wave_playback_service.c.dart | 4 ++-- lib/app/services/browser/browser.dart | 2 +- .../compressor/compress_service.c.dart | 18 +++++++------- .../ion_identity/ion_identity_provider.c.dart | 2 +- lib/app/services/logger/logger.dart | 24 +++++++------------ .../services/media_service/album_service.dart | 2 +- .../media_service/banuba_service.c.dart | 6 ++--- .../media_service/media_service.c.dart | 4 ++-- lib/app/services/nostr/nostr_logger.dart | 8 +++---- lib/app/utils/retry.dart | 4 ++-- 26 files changed, 73 insertions(+), 79 deletions(-) diff --git a/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart b/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart index 18c345385..08f8d044c 100644 --- a/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart +++ b/lib/app/features/auth/providers/onboarding_complete_notifier.c.dart @@ -205,7 +205,7 @@ class OnboardingCompleteNotifier extends _$OnboardingCompleteNotifier { } } catch (error, stackTrace) { // intentionally ignore upload avatar exceptions - Logger().log('Upload avatar exception', error: error, stackTrace: stackTrace); + Logger.log('Upload avatar exception', error: error, stackTrace: stackTrace); } return null; } diff --git a/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart b/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart index 3cd792b4b..8ddee2b7d 100644 --- a/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart +++ b/lib/app/features/chat/messages/views/components/message_item_wrapper/message_item_wrapper.dart @@ -41,7 +41,7 @@ class MessageItemWrapper extends HookWidget { ), ); } catch (e, st) { - Logger().log('Error showing message reaction dialog:', error: e, stackTrace: st); + Logger.log('Error showing message reaction dialog:', error: e, stackTrace: st); } }, [messageItemKey, isMe], diff --git a/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart b/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart index a76c11666..52b2fb0d8 100644 --- a/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart +++ b/lib/app/features/chat/messages/views/components/messaging_bottom_bar/components/more_content_view.dart @@ -54,7 +54,7 @@ class MoreContentView extends ConsumerWidget { ).push(context); //TODO: use contactId to share profile - Logger().log(contactId ?? 'No contact selected'); + Logger.log(contactId ?? 'No contact selected'); ref.read(messagingBottomBarActiveStateProvider.notifier).setText(); }, diff --git a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart index 045cb15b4..f4062f696 100644 --- a/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_actions_provider.c.dart @@ -87,7 +87,7 @@ class ConversationMessageActionsService { ['encrypted'], ]; - Logger().log('Encoded rumor $encodedRumor'); + Logger.log('Encoded rumor $encodedRumor'); final encryptedRumor = await Nip44.encryptMessage( encodedRumor, @@ -95,7 +95,7 @@ class ConversationMessageActionsService { receiverPubkey, ); - Logger().log('Encrypted rumor $encryptedRumor'); + Logger.log('Encrypted rumor $encryptedRumor'); final id = EventMessage.calculateEventId( tags: tags, @@ -115,7 +115,7 @@ class ConversationMessageActionsService { sig: null, ); - Logger().log('Bookmark message $bookmarkMessage'); + Logger.log('Bookmark message $bookmarkMessage'); await nostrNotifier.sendEvent(bookmarkMessage, cache: false); } @@ -211,7 +211,7 @@ class ConversationMessageActionsService { sig: await signer.sign(message: id), ); - Logger().log('Event message $eventMessage'); + Logger.log('Event message $eventMessage'); final seal = await sealService.createSeal( eventMessage, @@ -219,7 +219,7 @@ class ConversationMessageActionsService { receiverPubkey, ); - Logger().log('Seal message $seal'); + Logger.log('Seal message $seal'); final expirationTag = EntityExpiration( value: DateTime.now().add( @@ -235,11 +235,11 @@ class ConversationMessageActionsService { expirationTag: expirationTag, ); - Logger().log('Wrap message $wrap'); + Logger.log('Wrap message $wrap'); final result = await nostrNotifier.sendEvent(wrap, cache: false); - Logger().log('Sent message $result'); + Logger.log('Sent message $result'); return result; } diff --git a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart index 4a4967b70..006a09673 100644 --- a/lib/app/features/chat/providers/conversation_message_management_provider.c.dart +++ b/lib/app/features/chat/providers/conversation_message_management_provider.c.dart @@ -101,7 +101,7 @@ class ConversationMessageManagementService { alt: FileAlt.message, ); - Logger().log( + Logger.log( 'Uploaded media file: ${uploadResult.fileMetadata.url}, ${uploadResult.fileMetadata.mimeType} ${uploadResult.fileMetadata.size}', ); @@ -147,7 +147,7 @@ class ConversationMessageManagementService { final decryptedDecompressedFiles = []; for (final attachment in privateDirectMessageEntity.data.media.values) { - Logger().log('Attachment: $attachment'); + Logger.log('Attachment: $attachment'); if (attachment.encryptionKey != null && attachment.encryptionNonce != null && attachment.encryptionMac != null) { @@ -157,7 +157,7 @@ class ConversationMessageManagementService { final file = await fileCacheService.getFile(attachment.url); - Logger().log( + Logger.log( 'Downloaded encrypted media file: ${file.path}, ${attachment.mimeType} ${file.lengthSync()}', ); @@ -184,7 +184,7 @@ class ConversationMessageManagementService { fileExtension: attachment.mimeType.split('/').last, ); - Logger().log( + Logger.log( 'Decrypted media file: ${decryptedFile.path}, ${attachment.mimeType} ${decryptedFile.lengthSync()}', ); @@ -238,7 +238,7 @@ class ConversationMessageManagementService { sig: null, ); - Logger().log('Event message $eventMessage'); + Logger.log('Event message $eventMessage'); final seal = await sealService.createSeal( eventMessage, @@ -246,7 +246,7 @@ class ConversationMessageManagementService { receiverPubkey, ); - Logger().log('Seal message $seal'); + Logger.log('Seal message $seal'); final wrap = await wrapService.createWrap( seal, @@ -255,11 +255,11 @@ class ConversationMessageManagementService { PrivateDirectMessageEntity.kind, ); - Logger().log('Wrap message $wrap'); + Logger.log('Wrap message $wrap'); final result = await nostrNotifier.sendEvent(wrap, cache: false); - Logger().log('Sent message $result'); + Logger.log('Sent message $result'); return result; } @@ -273,7 +273,7 @@ class ConversationMessageManagementService { mediaFiles.map( (mediaFile) async { final size = File(mediaFile.path).lengthSync(); - Logger().log( + Logger.log( 'Original media file: ${mediaFile.path}, ${mediaFile.mimeType} $size', ); @@ -298,7 +298,7 @@ class ConversationMessageManagementService { }; final compressedSize = File(compressedMediaFile.path).lengthSync(); - Logger().log( + Logger.log( 'Compressed media file: ${compressedMediaFile.path}, ${compressedMediaFile.mimeType} $compressedSize', ); @@ -342,7 +342,7 @@ class ConversationMessageManagementService { mimeType: compressedMediaFile.mimeType, ); - Logger().log( + Logger.log( 'Encrypted media file ${compressedEncryptedMediaFile.mimeType} ${compressedEncryptedFile.lengthSync()}', ); diff --git a/lib/app/features/core/providers/dio_provider.c.dart b/lib/app/features/core/providers/dio_provider.c.dart index f0aab814a..583bda8db 100644 --- a/lib/app/features/core/providers/dio_provider.c.dart +++ b/lib/app/features/core/providers/dio_provider.c.dart @@ -11,7 +11,7 @@ part 'dio_provider.c.g.dart'; Dio dio(Ref ref) { final dio = Dio(); - final logger = Logger().talkerDioLogger; + final logger = Logger.talkerDioLogger; if (logger != null) { dio.interceptors.add(logger); diff --git a/lib/app/features/core/providers/init_provider.c.dart b/lib/app/features/core/providers/init_provider.c.dart index d2dceae71..87d1f24c3 100644 --- a/lib/app/features/core/providers/init_provider.c.dart +++ b/lib/app/features/core/providers/init_provider.c.dart @@ -23,7 +23,7 @@ Future initApp(Ref ref) async { final logApp = featureFlagsNotifier.get(LoggerFeatureFlag.logApp); final logNostrDart = featureFlagsNotifier.get(LoggerFeatureFlag.logNostrDart); - if (logApp) Logger().init(); + if (logApp) Logger.init(); Nostr.initialize(logNostrDart ? NostrLogger() : null); diff --git a/lib/app/features/core/views/pages/error_modal.dart b/lib/app/features/core/views/pages/error_modal.dart index 55978fed7..66bff2f49 100644 --- a/lib/app/features/core/views/pages/error_modal.dart +++ b/lib/app/features/core/views/pages/error_modal.dart @@ -15,7 +15,7 @@ import 'package:ion/generated/assets.gen.dart'; class ErrorModal extends ConsumerWidget { ErrorModal({required this.error, super.key}) { - Logger().error(error); + Logger.error(error); } final Object error; diff --git a/lib/app/features/debug/views/debug_page.dart b/lib/app/features/debug/views/debug_page.dart index 2f620342d..ab259ff8c 100644 --- a/lib/app/features/debug/views/debug_page.dart +++ b/lib/app/features/debug/views/debug_page.dart @@ -15,7 +15,7 @@ class DebugPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final featureFlags = ref.watch(featureFlagsProvider); - final talker = Logger().talker; + final talker = Logger.talker; return Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart b/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart index 9356ac666..4a92a9438 100644 --- a/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart +++ b/lib/app/features/feed/create_post/views/pages/create_post_modal/hooks/use_has_poll.dart @@ -58,7 +58,7 @@ bool _containsPollKey(dynamic customData) { try { parsedData = jsonDecode(customData) as Map?; } catch (e) { - Logger().log('Failed to parse custom data: $e'); + Logger.log('Failed to parse custom data: $e'); } } diff --git a/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart b/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart index 43b5c4486..9d659ce2f 100644 --- a/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart +++ b/lib/app/features/feed/providers/article/suggestions_notifier_provider.c.dart @@ -27,7 +27,7 @@ class SuggestionsNotifier extends _$SuggestionsNotifier { newSuggestions = await ref.read(mentionSuggestionsProvider(query).future); } } catch (error) { - Logger().log('Error fetching suggestions: $error'); + Logger.log('Error fetching suggestions: $error'); } state = newSuggestions; diff --git a/lib/app/features/gallery/providers/camera_provider.c.dart b/lib/app/features/gallery/providers/camera_provider.c.dart index 32f70bdf3..6ee1d7ad1 100644 --- a/lib/app/features/gallery/providers/camera_provider.c.dart +++ b/lib/app/features/gallery/providers/camera_provider.c.dart @@ -66,7 +66,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final initialCamera = _backCamera ?? _frontCamera; if (initialCamera == null) { - Logger().log('Camera not found'); + Logger.log('Camera not found'); state = const CameraState.error(message: 'Camera not found'); return; } @@ -74,7 +74,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final controller = await _createCameraController(initialCamera); state = CameraState.ready(controller: controller); } catch (e) { - Logger().log('Camera initialization error: $e'); + Logger.log('Camera initialization error: $e'); state = CameraState.error(message: 'Camera initialization error: $e'); } } @@ -90,7 +90,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { _cameraController?.addListener(_onCameraControllerUpdate); return _cameraController!; } catch (e) { - Logger().log('Camera initialization error: $e'); + Logger.log('Camera initialization error: $e'); await _disposeCamera(); throw Exception('Camera initialization error: $e'); } @@ -154,7 +154,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: mode == FlashMode.torch, ); } catch (e) { - Logger().log('Error setting flash mode', error: e); + Logger.log('Error setting flash mode', error: e); state = CameraState.error(message: 'Error setting flash mode: $e'); } }, @@ -174,7 +174,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: !isFlashOn, ); } catch (e) { - Logger().log('Error toggling flash mode', error: e); + Logger.log('Error toggling flash mode', error: e); state = CameraState.error(message: 'Error toggling flash mode: $e'); } }, @@ -189,7 +189,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { final picture = await _cameraController!.takePicture(); return picture; } catch (e) { - Logger().log('Error taking picture', error: e); + Logger.log('Error taking picture', error: e); return null; } } @@ -206,7 +206,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { isFlashOn: isFlashOn, ); } catch (e) { - Logger().log('Error starting video recording', error: e); + Logger.log('Error starting video recording', error: e); state = CameraState.error(message: 'Error starting video recording: $e'); } } @@ -240,7 +240,7 @@ class CameraControllerNotifier extends _$CameraControllerNotifier { return videoFile; } catch (e) { - Logger().log('Error stopping video recording', error: e); + Logger.log('Error stopping video recording', error: e); state = CameraState.error(message: 'Error stopping video recording: $e'); return null; } diff --git a/lib/app/features/gallery/providers/gallery_provider.c.dart b/lib/app/features/gallery/providers/gallery_provider.c.dart index fab286d49..45a6a0d64 100644 --- a/lib/app/features/gallery/providers/gallery_provider.c.dart +++ b/lib/app/features/gallery/providers/gallery_provider.c.dart @@ -53,7 +53,7 @@ class GalleryNotifier extends _$GalleryNotifier { final hasPermission = ref.read(hasPermissionProvider(Permission.photos)); if (!hasPermission) { - Logger().log('Photos Permission denied'); + Logger.log('Photos Permission denied'); return GalleryState( mediaData: [], currentPage: 0, diff --git a/lib/app/features/nostr/providers/nostr_notifier.c.dart b/lib/app/features/nostr/providers/nostr_notifier.c.dart index 6f48ba542..d5d4c4f39 100644 --- a/lib/app/features/nostr/providers/nostr_notifier.c.dart +++ b/lib/app/features/nostr/providers/nostr_notifier.c.dart @@ -173,7 +173,7 @@ class NostrNotifier extends _$NostrNotifier { try { yield _parseAndCache(event); } catch (error, stackTrace) { - Logger().log('Failed to process event ${event.id}', error: error, stackTrace: stackTrace); + Logger.log('Failed to process event ${event.id}', error: error, stackTrace: stackTrace); } } } diff --git a/lib/app/features/user/providers/user_relays_manager.c.dart b/lib/app/features/user/providers/user_relays_manager.c.dart index bd1a50f1f..6bc63c640 100644 --- a/lib/app/features/user/providers/user_relays_manager.c.dart +++ b/lib/app/features/user/providers/user_relays_manager.c.dart @@ -91,7 +91,7 @@ class UserRelaysManager extends _$UserRelaysManager { try { return await ionIdentity.users.details(userId: pubkey); } catch (error, stackTrace) { - Logger().log('Error fetching user relays', error: error, stackTrace: stackTrace); + Logger.log('Error fetching user relays', error: error, stackTrace: stackTrace); } }), ); diff --git a/lib/app/router/providers/go_router_provider.c.dart b/lib/app/router/providers/go_router_provider.c.dart index 3405526d5..8cec5edf8 100644 --- a/lib/app/router/providers/go_router_provider.c.dart +++ b/lib/app/router/providers/go_router_provider.c.dart @@ -36,7 +36,7 @@ GoRouter goRouter(Ref ref) { final isInitError = initState.hasError; if (isInitError) { - Logger().log('Init error', error: initState.error); + Logger.log('Init error', error: initState.error); return ErrorRoute().location; } diff --git a/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart b/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart index 3eebff484..8fb6ffbeb 100644 --- a/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart +++ b/lib/app/services/audio_wave_playback_service/audio_wave_playback_service.c.dart @@ -33,7 +33,7 @@ class AudioWavePlaybackService { await preparePlayer(savedFilePath, audioPlaybackController, playerWaveStyle); } } catch (e, s) { - Logger().log('Error initializing player', error: e, stackTrace: s); + Logger.log('Error initializing player', error: e, stackTrace: s); } } @@ -48,7 +48,7 @@ class AudioWavePlaybackService { noOfSamples: playerWaveStyle.getSamplesForWidth(158.0.s), ); } catch (e, s) { - Logger().log('Error preparing player', error: e, stackTrace: s); + Logger.log('Error preparing player', error: e, stackTrace: s); } } diff --git a/lib/app/services/browser/browser.dart b/lib/app/services/browser/browser.dart index 6a47ad6d7..b7fc28233 100644 --- a/lib/app/services/browser/browser.dart +++ b/lib/app/services/browser/browser.dart @@ -15,7 +15,7 @@ Future openUrl( return false; } } catch (error) { - Logger().log('Could not launch $url', error: error); + Logger.log('Could not launch $url', error: error); return false; } } diff --git a/lib/app/services/compressor/compress_service.c.dart b/lib/app/services/compressor/compress_service.c.dart index 0c2a65709..f8f49192d 100644 --- a/lib/app/services/compressor/compress_service.c.dart +++ b/lib/app/services/compressor/compress_service.c.dart @@ -84,13 +84,13 @@ class CompressionService { final match = RegExp(r'Stream.*Video:.* (\d+)x(\d+)').firstMatch(logs); if (match == null) { - Logger().log('Failed to compress video. Dimension not found. Logs: $logs'); + Logger.log('Failed to compress video. Dimension not found. Logs: $logs'); throw CompressVideoException('no-dim'); } if (!ReturnCode.isSuccess(returnCode)) { final stackTrace = await session.getFailStackTrace(); - Logger().log('Failed to compress video. Logs: $logs, StackTrace: $stackTrace'); + Logger.log('Failed to compress video. Logs: $logs, StackTrace: $stackTrace'); throw CompressVideoException(returnCode); } @@ -101,7 +101,7 @@ class CompressionService { height: int.parse(match.group(2)!), ); } catch (error, stackTrace) { - Logger().log('Error during video compression!', error: error, stackTrace: stackTrace); + Logger.log('Error during video compression!', error: error, stackTrace: stackTrace); rethrow; } } @@ -144,7 +144,7 @@ class CompressionService { height: outputDimension.height, ); } catch (error, stackTrace) { - Logger().log('Error during image compression!', error: error, stackTrace: stackTrace); + Logger.log('Error during image compression!', error: error, stackTrace: stackTrace); rethrow; } } @@ -169,7 +169,7 @@ class CompressionService { } final logs = await session.getAllLogsAsString(); final stackTrace = await session.getFailStackTrace(); - Logger().log('Failed to convert audio to opus. Logs: $logs, StackTrace: $stackTrace'); + Logger.log('Failed to convert audio to opus. Logs: $logs, StackTrace: $stackTrace'); throw CompressAudioException(); }); } @@ -195,7 +195,7 @@ class CompressionService { } final logs = await session.getAllLogsAsString(); final stackTrace = await session.getFailStackTrace(); - Logger().log('Failed to convert audio to wav. Logs: $logs, StackTrace: $stackTrace'); + Logger.log('Failed to convert audio to wav. Logs: $logs, StackTrace: $stackTrace'); throw CompressAudioToWavException(); }); } @@ -246,7 +246,7 @@ class CompressionService { return compressedImage; } catch (error, stackTrace) { - Logger().log('Error during thumbnail extraction!', error: error, stackTrace: stackTrace); + Logger.log('Error during thumbnail extraction!', error: error, stackTrace: stackTrace); rethrow; } } @@ -271,7 +271,7 @@ class CompressionService { return _saveBytesIntoFile(bytes: compressedData, extension: 'br'); } catch (error, stackTrace) { - Logger().log('Error during Brotli compression!', error: error, stackTrace: stackTrace); + Logger.log('Error during Brotli compression!', error: error, stackTrace: stackTrace); throw CompressWithBrotliException(); } } @@ -287,7 +287,7 @@ class CompressionService { ); return _saveBytesIntoFile(bytes: decompressedData, extension: outputExtension); } catch (error, stackTrace) { - Logger().log('Error during Brotli decompression!', error: error, stackTrace: stackTrace); + Logger.log('Error during Brotli decompression!', error: error, stackTrace: stackTrace); throw DecompressBrotliException(); } } diff --git a/lib/app/services/ion_identity/ion_identity_provider.c.dart b/lib/app/services/ion_identity/ion_identity_provider.c.dart index d13b41237..aa2074fc0 100644 --- a/lib/app/services/ion_identity/ion_identity_provider.c.dart +++ b/lib/app/services/ion_identity/ion_identity_provider.c.dart @@ -26,7 +26,7 @@ Future> ionIdentity(Ref ref) async { final config = IONIdentityConfig( appId: appId, origin: env.get(EnvVariable.ION_ORIGIN), - logger: logIonIdentityClient ? Logger().talkerDioLogger : null, + logger: logIonIdentityClient ? Logger.talkerDioLogger : null, ); final ionClient = IONIdentity.createDefault(config: config); diff --git a/lib/app/services/logger/logger.dart b/lib/app/services/logger/logger.dart index 44806e691..165125264 100644 --- a/lib/app/services/logger/logger.dart +++ b/lib/app/services/logger/logger.dart @@ -5,23 +5,17 @@ import 'package:talker_dio_logger/talker_dio_logger_settings.dart'; import 'package:talker_flutter/talker_flutter.dart'; class Logger { - factory Logger() { - return _instance; - } - Logger._(); - static final Logger _instance = Logger._(); - - Talker? _talker; + static Talker? _talker; - Talker? get talker => _talker; - - void init() { + static void init() { _talker = TalkerFlutter.init(); } - TalkerDioLogger? get talkerDioLogger => TalkerDioLogger( + static Talker? get talker => _talker; + + static TalkerDioLogger? get talkerDioLogger => TalkerDioLogger( talker: talker, settings: TalkerDioLoggerSettings( printRequestHeaders: true, @@ -32,7 +26,7 @@ class Logger { ), ); - void log( + static void log( String message, { Object? error, StackTrace? stackTrace, @@ -44,15 +38,15 @@ class Logger { } } - void info(String message) { + static void info(String message) { _talker?.info(message); } - void warning(String message) { + static void warning(String message) { _talker?.warning(message); } - void error( + static void error( Object error, { StackTrace? stackTrace, }) { diff --git a/lib/app/services/media_service/album_service.dart b/lib/app/services/media_service/album_service.dart index cb201ccf3..49f58b88e 100644 --- a/lib/app/services/media_service/album_service.dart +++ b/lib/app/services/media_service/album_service.dart @@ -49,7 +49,7 @@ class AlbumService { }) async { final assetPath = _albumsCache[albumId]; if (assetPath == null) { - Logger().log('Album not found in cache: $albumId'); + Logger.log('Album not found in cache: $albumId'); return []; } diff --git a/lib/app/services/media_service/banuba_service.c.dart b/lib/app/services/media_service/banuba_service.c.dart index feae6c2a8..73d25b327 100644 --- a/lib/app/services/media_service/banuba_service.c.dart +++ b/lib/app/services/media_service/banuba_service.c.dart @@ -60,7 +60,7 @@ class BanubaService { } return filePath; } on PlatformException catch (e) { - Logger().log( + Logger.log( 'Start Photo Editor error', error: e, stackTrace: StackTrace.current, @@ -92,7 +92,7 @@ Future editMedia(Ref ref, MediaFile mediaFile) async { final filePath = await ref.read(assetFilePathProvider(mediaFile.path).future); if (filePath == null) { - Logger().log( + Logger.log( 'File path or mime type is null', error: mediaFile, stackTrace: StackTrace.current, @@ -101,7 +101,7 @@ Future editMedia(Ref ref, MediaFile mediaFile) async { } if (mediaFile.mimeType == null) { - Logger().log( + Logger.log( 'Mime type is null', error: mediaFile, stackTrace: StackTrace.current, diff --git a/lib/app/services/media_service/media_service.c.dart b/lib/app/services/media_service/media_service.c.dart index ff0c92b9c..454831f51 100644 --- a/lib/app/services/media_service/media_service.c.dart +++ b/lib/app/services/media_service/media_service.c.dart @@ -88,7 +88,7 @@ class MediaService { return mediaFiles; } catch (e) { - Logger().log('Error fetching gallery images: $e'); + Logger.log('Error fetching gallery images: $e'); return []; } } @@ -198,7 +198,7 @@ class MediaService { } return null; } catch (e, st) { - Logger().log('Error capturing widget as image:', error: e, stackTrace: st); + Logger.log('Error capturing widget as image:', error: e, stackTrace: st); return null; } } diff --git a/lib/app/services/nostr/nostr_logger.dart b/lib/app/services/nostr/nostr_logger.dart index 81654d689..d17f2acc0 100644 --- a/lib/app/services/nostr/nostr_logger.dart +++ b/lib/app/services/nostr/nostr_logger.dart @@ -8,19 +8,19 @@ class NostrLogger implements NostrDartLogger { @override void info(String message, [Object? error, StackTrace? stackTrace]) { - Logger().info('$_prefix $message'); + Logger.info('$_prefix $message'); if (error != null) { - Logger().error('$_prefix $error', stackTrace: stackTrace); + Logger.error('$_prefix $error', stackTrace: stackTrace); } } @override void warning(String message, [Object? error, StackTrace? stackTrace]) { - Logger().warning('$_prefix $message'); + Logger.warning('$_prefix $message'); if (error != null) { - Logger().error('$_prefix $error', stackTrace: stackTrace); + Logger.error('$_prefix $error', stackTrace: stackTrace); } } } diff --git a/lib/app/utils/retry.dart b/lib/app/utils/retry.dart index 679a3498b..e4d238bdd 100644 --- a/lib/app/utils/retry.dart +++ b/lib/app/utils/retry.dart @@ -59,7 +59,7 @@ Stream withRetryStream( rethrow; } - Logger().log(e.toString()); + Logger.log(e.toString()); attempt++; if (attempt >= maxRetries) { rethrow; @@ -73,7 +73,7 @@ Stream withRetryStream( maxJitter: maxJitter, ); - Logger().log('Retry #$attempt after ${delay.inMilliseconds}ms...'); + Logger.log('Retry #$attempt after ${delay.inMilliseconds}ms...'); await Future.delayed(delay); } onRetry?.call();