diff --git a/app/lib/features/bangs/data/models/bang_key.dart b/app/lib/features/bangs/data/models/bang_key.dart index 1f6d17b1..2dbdba6d 100644 --- a/app/lib/features/bangs/data/models/bang_key.dart +++ b/app/lib/features/bangs/data/models/bang_key.dart @@ -19,6 +19,7 @@ */ import 'package:json_annotation/json_annotation.dart'; import 'package:nullability/nullability.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/bangs/data/models/bang_group.dart'; class BangKey { @@ -50,7 +51,8 @@ class BangKey { group: BangGroup.values.firstWhere((g) => g.name == group), trigger: trigger, ); - } catch (_) { + } catch (e, s) { + logger.w('Failed to parse BangKey from string: "$key"', error: e, stackTrace: s); return null; } } diff --git a/app/lib/features/geckoview/domain/providers/selected_tab.dart b/app/lib/features/geckoview/domain/providers/selected_tab.dart index e3ec89d0..b362bbc2 100644 --- a/app/lib/features/geckoview/domain/providers/selected_tab.dart +++ b/app/lib/features/geckoview/domain/providers/selected_tab.dart @@ -47,9 +47,14 @@ class SelectedTab extends _$SelectedTab { }, ); - final selectedTabSub = eventSerivce.selectedTabEvents.listen((tabId) { - state = tabId; - }); + final selectedTabSub = eventSerivce.selectedTabEvents.listen( + (tabId) { + state = tabId; + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in selected tab events', error: error, stackTrace: stackTrace); + }, + ); ref.onDispose(() async { await selectedTabSub.cancel(); diff --git a/app/lib/features/geckoview/domain/providers/selected_tab.g.dart b/app/lib/features/geckoview/domain/providers/selected_tab.g.dart index 70876cad..46f2fc4d 100644 --- a/app/lib/features/geckoview/domain/providers/selected_tab.g.dart +++ b/app/lib/features/geckoview/domain/providers/selected_tab.g.dart @@ -41,7 +41,7 @@ final class SelectedTabProvider } } -String _$selectedTabHash() => r'26d1bb90c777d7011f4f27f7b962584a4a62a0a7'; +String _$selectedTabHash() => r'5caa359376e9103767e2d2e94c548d53cba79d0f'; abstract class _$SelectedTab extends $Notifier { String? build(); diff --git a/app/lib/features/geckoview/domain/providers/tab_list.dart b/app/lib/features/geckoview/domain/providers/tab_list.dart index e2de1612..581ff98e 100644 --- a/app/lib/features/geckoview/domain/providers/tab_list.dart +++ b/app/lib/features/geckoview/domain/providers/tab_list.dart @@ -48,13 +48,18 @@ class TabList extends _$TabList { }, ); - final tabListSub = eventService.tabListEvents.listen((tabs) { - final equatableTabs = EquatableValue(tabs); + final tabListSub = eventService.tabListEvents.listen( + (tabs) { + final equatableTabs = EquatableValue(tabs); - if (equatableTabs != state) { - state = equatableTabs; - } - }); + if (equatableTabs != state) { + state = equatableTabs; + } + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in tab list events', error: error, stackTrace: stackTrace); + }, + ); ref.onDispose(() async { await tabListSub.cancel(); diff --git a/app/lib/features/geckoview/domain/providers/tab_list.g.dart b/app/lib/features/geckoview/domain/providers/tab_list.g.dart index b1a14975..fba8372c 100644 --- a/app/lib/features/geckoview/domain/providers/tab_list.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_list.g.dart @@ -41,7 +41,7 @@ final class TabListProvider } } -String _$tabListHash() => r'0b9ca1e089a59895df4cbf28691c2849a7004f08'; +String _$tabListHash() => r'88c2598a4d586fee9e3d0f1b418cf88ea5c7da75'; abstract class _$TabList extends $Notifier>> { EquatableValue> build(); diff --git a/app/lib/features/geckoview/domain/providers/tab_state.dart b/app/lib/features/geckoview/domain/providers/tab_state.dart index f1adeeca..68cc1c66 100644 --- a/app/lib/features/geckoview/domain/providers/tab_state.dart +++ b/app/lib/features/geckoview/domain/providers/tab_state.dart @@ -218,29 +218,64 @@ class TabStates extends _$TabStates { final eventService = ref.watch(eventServiceProvider); final subscriptions = [ - eventService.tabContentEvents.listen((event) async { - await _onTabContentStateChange(event); - }), - eventService.iconChangeEvents.listen((event) async { - await _onIconChange(event); - }), - eventService.thumbnailEvents.listen((event) async { - await _onThumbnailChange(event); - }), - eventService.securityInfoEvents.listen((event) { - _onSecurityInfoStateChange(event); - }), - eventService.historyEvents.listen((event) { - _onHistoryStateChange(event); - }), - eventService.readerableEvents.listen((event) { - _onReaderableStateChange(event); - }), + eventService.tabContentEvents.listen( + (event) async { + await _onTabContentStateChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in tab content events', error: error, stackTrace: stackTrace); + }, + ), + eventService.iconChangeEvents.listen( + (event) async { + await _onIconChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in icon change events', error: error, stackTrace: stackTrace); + }, + ), + eventService.thumbnailEvents.listen( + (event) async { + await _onThumbnailChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in thumbnail events', error: error, stackTrace: stackTrace); + }, + ), + eventService.securityInfoEvents.listen( + (event) { + _onSecurityInfoStateChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in security info events', error: error, stackTrace: stackTrace); + }, + ), + eventService.historyEvents.listen( + (event) { + _onHistoryStateChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in history events', error: error, stackTrace: stackTrace); + }, + ), + eventService.readerableEvents.listen( + (event) { + _onReaderableStateChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in readerable events', error: error, stackTrace: stackTrace); + }, + ), eventService.findResultsEvent .debounceTime(const Duration(milliseconds: 25)) - .listen((event) { - _onFindResultsChange(event); - }), + .listen( + (event) { + _onFindResultsChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in find results events', error: error, stackTrace: stackTrace); + }, + ), ]; ref.listen( diff --git a/app/lib/features/geckoview/domain/providers/tab_state.g.dart b/app/lib/features/geckoview/domain/providers/tab_state.g.dart index ca3ddb1c..d957e5bb 100644 --- a/app/lib/features/geckoview/domain/providers/tab_state.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_state.g.dart @@ -41,7 +41,7 @@ final class TabStatesProvider } } -String _$tabStatesHash() => r'67b497304b4137ce0115a66f06f3622c86e5727d'; +String _$tabStatesHash() => r'985d2eb87c59c3a113b8bbcf9d96267c42a2f543'; abstract class _$TabStates extends $Notifier> { Map build(); diff --git a/app/lib/features/geckoview/domain/providers/web_extensions_state.dart b/app/lib/features/geckoview/domain/providers/web_extensions_state.dart index 305eedcf..b9f36d48 100644 --- a/app/lib/features/geckoview/domain/providers/web_extensions_state.dart +++ b/app/lib/features/geckoview/domain/providers/web_extensions_state.dart @@ -23,6 +23,7 @@ import 'dart:ui'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:nullability/nullability.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/domain/entities/equatable_image.dart'; import 'package:weblibre/features/geckoview/domain/entities/states/web_extension.dart'; import 'package:weblibre/features/geckoview/domain/providers.dart'; @@ -100,20 +101,40 @@ class WebExtensionsState extends _$WebExtensionsState { final subscriptions = switch (actionType) { WebExtensionActionType.browser => [ - addonService.browserExtensionStream.listen((event) { - _onExtensionUpdate(event); - }), - addonService.browserIconStream.listen((event) async { - await _onIconChange(event); - }), + addonService.browserExtensionStream.listen( + (event) { + _onExtensionUpdate(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in browser extension stream', error: error, stackTrace: stackTrace); + }, + ), + addonService.browserIconStream.listen( + (event) async { + await _onIconChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in browser icon stream', error: error, stackTrace: stackTrace); + }, + ), ], WebExtensionActionType.page => [ - addonService.pageExtensionStream.listen((event) { - _onExtensionUpdate(event); - }), - addonService.pageIconStream.listen((event) async { - await _onIconChange(event); - }), + addonService.pageExtensionStream.listen( + (event) { + _onExtensionUpdate(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in page extension stream', error: error, stackTrace: stackTrace); + }, + ), + addonService.pageIconStream.listen( + (event) async { + await _onIconChange(event); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in page icon stream', error: error, stackTrace: stackTrace); + }, + ), ], }; diff --git a/app/lib/features/geckoview/domain/providers/web_extensions_state.g.dart b/app/lib/features/geckoview/domain/providers/web_extensions_state.g.dart index 4086cea5..b2c8e1fe 100644 --- a/app/lib/features/geckoview/domain/providers/web_extensions_state.g.dart +++ b/app/lib/features/geckoview/domain/providers/web_extensions_state.g.dart @@ -62,7 +62,7 @@ final class WebExtensionsStateProvider } String _$webExtensionsStateHash() => - r'2664a50bb776197010e9da9b4e3a9379c849ba75'; + r'd74f739a2f33395c10e30a81c8031f2f2630e418'; final class WebExtensionsStateFamily extends $Family with diff --git a/app/lib/features/geckoview/domain/repositories/tab.dart b/app/lib/features/geckoview/domain/repositories/tab.dart index 30c31c6c..2cd1d788 100644 --- a/app/lib/features/geckoview/domain/repositories/tab.dart +++ b/app/lib/features/geckoview/domain/repositories/tab.dart @@ -424,16 +424,21 @@ class TabRepository extends _$TabRepository { final db = ref.watch(tabDatabaseProvider); - final tabAddedSub = eventSerivce.tabAddedStream.listen((tabId) async { - final containerId = ref.read(selectedContainerProvider); - await db.tabDao.insertTab( - tabId, - parentId: const Value.absent(), - source: TabSource.addedEvent, - containerId: Value(containerId), - isPrivate: const Value.absent(), - ); - }); + final tabAddedSub = eventSerivce.tabAddedStream.listen( + (tabId) async { + final containerId = ref.read(selectedContainerProvider); + await db.tabDao.insertTab( + tabId, + parentId: const Value.absent(), + source: TabSource.addedEvent, + containerId: Value(containerId), + isPrivate: const Value.absent(), + ); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in tab added stream', error: error, stackTrace: stackTrace); + }, + ); final containerSiteAssignementSub = eventSerivce.siteAssignementEvent.listen(( event, @@ -522,20 +527,27 @@ class TabRepository extends _$TabRepository { logger.w('Could not get tab for assignement ${tabState?.url}'); } } - }); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in container site assignment stream', error: error, stackTrace: stackTrace); + }, + ); - final tabContentSub = tabContentService.tabContentStream.listen(( - content, - ) async { - await db.tabDao.updateTabContent( - content.tabId, - isProbablyReaderable: content.isProbablyReaderable, - extractedContentMarkdown: content.extractedContentMarkdown, - extractedContentPlain: content.extractedContentPlain, - fullContentMarkdown: content.fullContentMarkdown, - fullContentPlain: content.fullContentPlain, - ); - }); + final tabContentSub = tabContentService.tabContentStream.listen( + (content) async { + await db.tabDao.updateTabContent( + content.tabId, + isProbablyReaderable: content.isProbablyReaderable, + extractedContentMarkdown: content.extractedContentMarkdown, + extractedContentPlain: content.extractedContentPlain, + fullContentMarkdown: content.fullContentMarkdown, + fullContentPlain: content.fullContentPlain, + ); + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in tab content stream', error: error, stackTrace: stackTrace); + }, + ); ref.listen( fireImmediately: true, @@ -545,7 +557,7 @@ class TabRepository extends _$TabRepository { await db.tabDao.touchTab(tabId, timestamp: DateTime.now()); } }, - onError: (error, stackTrace) { + onError: (Object error, StackTrace stackTrace) { logger.e( 'Error listening to selectedTabProvider', error: error, @@ -565,7 +577,7 @@ class TabRepository extends _$TabRepository { await db.tabDao.syncTabs(retainTabIds: next.value); } }, - onError: (error, stackTrace) { + onError: (Object error, StackTrace stackTrace) { logger.e( 'Error listening to tabListProvider', error: error, @@ -591,7 +603,7 @@ class TabRepository extends _$TabRepository { await db.tabDao.updateTabs(debounceStartValue, next); }); }, - onError: (error, stackTrace) { + onError: (Object error, StackTrace stackTrace) { logger.e( 'Error listening to tabStatesProvider', error: error, diff --git a/app/lib/features/geckoview/domain/repositories/tab.g.dart b/app/lib/features/geckoview/domain/repositories/tab.g.dart index 6964b7b8..138fa88d 100644 --- a/app/lib/features/geckoview/domain/repositories/tab.g.dart +++ b/app/lib/features/geckoview/domain/repositories/tab.g.dart @@ -41,7 +41,7 @@ final class TabRepositoryProvider } } -String _$tabRepositoryHash() => r'763f5ea734abc854dfdc0c08d3f266fbd94bf931'; +String _$tabRepositoryHash() => r'ff8ce73a65d408587cfb41e1920332d15ddff55f'; abstract class _$TabRepository extends $Notifier { void build(); diff --git a/app/lib/features/geckoview/features/bookmarks/presentation/screens/bookmark_list.dart b/app/lib/features/geckoview/features/bookmarks/presentation/screens/bookmark_list.dart index d389d1be..bcef9c48 100644 --- a/app/lib/features/geckoview/features/bookmarks/presentation/screens/bookmark_list.dart +++ b/app/lib/features/geckoview/features/bookmarks/presentation/screens/bookmark_list.dart @@ -29,6 +29,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:nullability/nullability.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/features/geckoview/features/bookmarks/domain/entities/bookmark_item.dart'; import 'package:weblibre/features/geckoview/features/bookmarks/domain/providers/bookmarks.dart'; @@ -405,7 +406,8 @@ class BookmarkListScreen extends HookConsumerWidget { if (context.mounted) { showInfoMessage(context, 'Imported $count bookmarks successfully'); } - } catch (e) { + } catch (e, s) { + logger.e('Bookmark import failed', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Import failed: $e'); } @@ -454,7 +456,8 @@ class BookmarkListScreen extends HookConsumerWidget { if (context.mounted) { showInfoMessage(context, 'Bookmarks exported successfully'); } - } catch (e) { + } catch (e, s) { + logger.e('Bookmark export failed', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Export failed: $e'); } diff --git a/app/lib/features/geckoview/features/browser/domain/providers/intent.dart b/app/lib/features/geckoview/features/browser/domain/providers/intent.dart index d51e2b02..b039f713 100644 --- a/app/lib/features/geckoview/features/browser/domain/providers/intent.dart +++ b/app/lib/features/geckoview/features/browser/domain/providers/intent.dart @@ -22,6 +22,7 @@ import 'dart:async'; import 'package:nullability/nullability.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/data/models/received_intent_parameter.dart'; import 'package:weblibre/features/app_widget/domain/services/home_widget.dart'; @@ -67,7 +68,10 @@ class EngineBoundIntentStream extends _$EngineBoundIntentStream { appWidgetLaunchStream.transform(_contentParserTransformer), ]).listen( controller.add, - onError: controller.addError, + onError: (Object error, StackTrace stackTrace) { + logger.e('Intent stream error', error: error, stackTrace: stackTrace); + controller.addError(error, stackTrace); + }, onDone: controller.close, ); diff --git a/app/lib/features/geckoview/features/browser/domain/providers/intent.g.dart b/app/lib/features/geckoview/features/browser/domain/providers/intent.g.dart index ec28289c..63f3d089 100644 --- a/app/lib/features/geckoview/features/browser/domain/providers/intent.g.dart +++ b/app/lib/features/geckoview/features/browser/domain/providers/intent.g.dart @@ -34,7 +34,7 @@ final class EngineBoundIntentStreamProvider } String _$engineBoundIntentStreamHash() => - r'ab9804f97e0222b2306683d2fcfa71d3d57ecd21'; + r'618eb6431da93989de6f1780cba2993458b0014e'; abstract class _$EngineBoundIntentStream extends $StreamNotifier { diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart index aef4c197..b70b047e 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart @@ -302,7 +302,7 @@ class _BrowserViewState extends ConsumerState await router.push(route.location); } else { - throw UnimplementedError(); + throw UnimplementedError('Unknown quick action shortcut type'); } } }); diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/clear_site_data_section.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/clear_site_data_section.dart index b0c55c9f..a6b24704 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/clear_site_data_section.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/clear_site_data_section.dart @@ -21,6 +21,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/dialogs/clear_site_data_dialog.dart'; import 'package:weblibre/utils/ui_helper.dart'; @@ -163,7 +164,8 @@ class ClearSiteDataSection extends HookConsumerWidget { if (context.mounted) { showInfoMessage(context, 'Site data cleared'); } - } catch (e) { + } catch (e, s) { + logger.e('Failed to clear site data', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Failed to clear site data: $e'); } diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/tracking_protection_section.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/tracking_protection_section.dart index 22234b80..e8bdbf92 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/tracking_protection_section.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/tracking_protection_section.dart @@ -20,6 +20,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:skeletonizer/skeletonizer.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/repositories/tracking_protection.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/tracking_protection_provider.dart'; @@ -102,7 +103,8 @@ class _TrackingProtectionTile extends ConsumerWidget { // Reload tab to apply changes await ref.read(selectedTabSessionProvider).reload(); - } catch (e) { + } catch (e, s) { + logger.e('Failed to toggle tracking protection', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Failed to toggle tracking protection: $e'); } diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_grid_view.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_grid_view.dart index aa53ad00..c9ee0481 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_grid_view.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_grid_view.dart @@ -82,7 +82,7 @@ class _TabDraggable extends HookConsumerWidget { sourceSearchQuery: switch (entity) { DefaultTabEntity _ => null, final SearchResultTabEntity entity => entity.searchQuery, - TabTreeEntity _ => throw UnimplementedError(), + TabTreeEntity _ => throw UnimplementedError('TabTreeEntity not implemented in tab grid view'), }, ); }, [entity.tabId, activeTab, suggestedContainerId]); diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_list_view.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_list_view.dart index 50c04ce3..70d8b4bf 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_list_view.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_list_view.dart @@ -83,7 +83,7 @@ class _TabDraggable extends HookConsumerWidget { sourceSearchQuery: switch (entity) { DefaultTabEntity _ => null, final SearchResultTabEntity entity => entity.searchQuery, - TabTreeEntity _ => throw UnimplementedError(), + TabTreeEntity _ => throw UnimplementedError('TabTreeEntity not implemented in tab list view'), }, ); }, [entity.tabId, activeTab, suggestedContainerId]); diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart index f22f86ed..9dda4d68 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart @@ -7,6 +7,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/features/geckoview/domain/providers.dart'; import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; @@ -484,7 +485,8 @@ class TabViewHeader extends HookConsumerWidget { : 'Container data cleared. ${tabs.length} tab(s) closed.', ); } - } catch (e) { + } catch (e, s) { + logger.e('Failed to clear container data', error: e, stackTrace: s); if (context.mounted) { ui_helper.showErrorMessage( context, diff --git a/app/lib/features/geckoview/features/history/presentation/screens/history.dart b/app/lib/features/geckoview/features/history/presentation/screens/history.dart index 0adf5387..f9ce2cf1 100644 --- a/app/lib/features/geckoview/features/history/presentation/screens/history.dart +++ b/app/lib/features/geckoview/features/history/presentation/screens/history.dart @@ -171,7 +171,7 @@ class Section extends MultiSliver { VisitType.download => const Text('Download'), VisitType.framedLink => const Text('Frame'), VisitType.reload => const Text('Page Reload'), - VisitType.bookmark => throw UnimplementedError(), + VisitType.bookmark => throw UnimplementedError('VisitType.bookmark chip display not implemented'), }, ), Chip( @@ -374,7 +374,7 @@ class HistoryScreen extends HookConsumerWidget { VisitType.download => const Text('Downloads'), VisitType.framedLink => const Text('Frames'), VisitType.reload => const Text('Page Reloads'), - VisitType.bookmark => throw UnimplementedError(), + VisitType.bookmark => throw UnimplementedError('VisitType.bookmark filter not implemented'), }, ), ), diff --git a/app/lib/features/geckoview/utils/image_helper.dart b/app/lib/features/geckoview/utils/image_helper.dart index 7f7ab191..c2decf05 100644 --- a/app/lib/features/geckoview/utils/image_helper.dart +++ b/app/lib/features/geckoview/utils/image_helper.dart @@ -21,6 +21,7 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:fast_equatable/hash.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/domain/entities/equatable_image.dart'; import 'package:weblibre/utils/lru_cache.dart'; @@ -64,8 +65,8 @@ Future tryDecodeImage( _cache.set(digest, image); return image; } - } catch (e) { - //swallow + } catch (e, s) { + logger.w('Failed to decode image', error: e, stackTrace: s); } return null; diff --git a/app/lib/features/settings/presentation/screens/tracking_protection_exceptions.dart b/app/lib/features/settings/presentation/screens/tracking_protection_exceptions.dart index f321fc99..5281f125 100644 --- a/app/lib/features/settings/presentation/screens/tracking_protection_exceptions.dart +++ b/app/lib/features/settings/presentation/screens/tracking_protection_exceptions.dart @@ -22,6 +22,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/repositories/tracking_protection.dart'; import 'package:weblibre/features/settings/presentation/dialogs/delete_all_exceptions_dialog.dart'; import 'package:weblibre/presentation/widgets/url_icon.dart'; @@ -99,7 +100,8 @@ class TrackingProtectionExceptionsScreen extends HookConsumerWidget { await ref .read(trackingProtectionRepositoryProvider.notifier) .removeAllExceptions(); - } catch (e) { + } catch (e, s) { + logger.e('Failed to delete tracking protection exceptions', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Failed to delete exceptions: $e'); } @@ -116,7 +118,8 @@ class TrackingProtectionExceptionsScreen extends HookConsumerWidget { await ref .read(trackingProtectionRepositoryProvider.notifier) .removeExceptionByUrl(exception.url); - } catch (e) { + } catch (e, s) { + logger.e('Failed to remove tracking protection exception', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Failed to remove exception: $e'); } diff --git a/app/lib/features/tor/domain/services/tor_proxy.dart b/app/lib/features/tor/domain/services/tor_proxy.dart index ebcfa279..efbc1d81 100644 --- a/app/lib/features/tor/domain/services/tor_proxy.dart +++ b/app/lib/features/tor/domain/services/tor_proxy.dart @@ -111,8 +111,8 @@ class TorProxyService extends _$TorProxyService { (setting) => setting.bridge.type == switch (torSettings.config) { - TorConnectionConfig.auto => throw UnimplementedError(), - TorConnectionConfig.direct => throw UnimplementedError(), + TorConnectionConfig.auto => throw UnimplementedError('TorConnectionConfig.auto bridge type not supported'), + TorConnectionConfig.direct => throw UnimplementedError('TorConnectionConfig.direct does not use bridges'), TorConnectionConfig.obfs4 => MoatTransportType.obfs4, TorConnectionConfig.snowflake => MoatTransportType.snowflake, diff --git a/app/lib/features/tor/domain/services/tor_proxy.g.dart b/app/lib/features/tor/domain/services/tor_proxy.g.dart index eda95485..75b1b950 100644 --- a/app/lib/features/tor/domain/services/tor_proxy.g.dart +++ b/app/lib/features/tor/domain/services/tor_proxy.g.dart @@ -33,7 +33,7 @@ final class TorProxyServiceProvider TorProxyService create() => TorProxyService(); } -String _$torProxyServiceHash() => r'0bf00b61bf7e739fe8c77696cf1b2a151d137671'; +String _$torProxyServiceHash() => r'7b430ca32fbfc9ebebb1e52271c0183efdf60971'; abstract class _$TorProxyService extends $StreamNotifier { Stream build(); diff --git a/app/lib/features/user/domain/repositories/cache.dart b/app/lib/features/user/domain/repositories/cache.dart index d8a96da0..9f9d6aa2 100644 --- a/app/lib/features/user/domain/repositories/cache.dart +++ b/app/lib/features/user/domain/repositories/cache.dart @@ -20,6 +20,7 @@ import 'dart:typed_data'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/domain/providers.dart'; import 'package:weblibre/features/user/data/providers.dart'; @@ -49,11 +50,16 @@ class CacheRepository extends _$CacheRepository { final db = ref.watch(userDatabaseProvider); - final sub = eventService.iconUpdateEvents.listen((event) async { - if (Uri.tryParse(event.url) case final Uri url) { - await db.cacheDao.cacheIcon(url.origin, event.bytes); - } - }); + final sub = eventService.iconUpdateEvents.listen( + (event) async { + if (Uri.tryParse(event.url) case final Uri url) { + await db.cacheDao.cacheIcon(url.origin, event.bytes); + } + }, + onError: (Object error, StackTrace stackTrace) { + logger.e('Error in icon update events', error: error, stackTrace: stackTrace); + }, + ); ref.onDispose(() async { await sub.cancel(); diff --git a/app/lib/features/user/domain/repositories/cache.g.dart b/app/lib/features/user/domain/repositories/cache.g.dart index 62ea1687..625c6bc6 100644 --- a/app/lib/features/user/domain/repositories/cache.g.dart +++ b/app/lib/features/user/domain/repositories/cache.g.dart @@ -41,7 +41,7 @@ final class CacheRepositoryProvider } } -String _$cacheRepositoryHash() => r'548b7cba9a23c21bba39f0918d7d90acaaf8d8e9'; +String _$cacheRepositoryHash() => r'e3cd7461aefe9e034a663169cd81ab7f69c2640e'; abstract class _$CacheRepository extends $Notifier { void build(); diff --git a/app/lib/features/user/domain/services/user_backup.dart b/app/lib/features/user/domain/services/user_backup.dart index 6eb31262..6c82d7bb 100644 --- a/app/lib/features/user/domain/services/user_backup.dart +++ b/app/lib/features/user/domain/services/user_backup.dart @@ -6,6 +6,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:secure_archive/secure_archive.dart'; import 'package:weblibre/core/filesystem.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/domain/entities/profile.dart'; import 'package:weblibre/features/user/domain/repositories/profile.dart'; @@ -95,8 +96,12 @@ class UserBackupService extends _$UserBackupService { if (await outputDirectory.exists()) { await outputDirectory.delete(recursive: true); } - } catch (_) { - // Ignore cleanup errors + } catch (e, s) { + logger.w( + 'Failed to cleanup temporary backup directory: ${outputDirectory.path}', + error: e, + stackTrace: s, + ); } } } diff --git a/app/lib/features/user/domain/services/user_backup.g.dart b/app/lib/features/user/domain/services/user_backup.g.dart index 2ed0db61..d236859f 100644 --- a/app/lib/features/user/domain/services/user_backup.g.dart +++ b/app/lib/features/user/domain/services/user_backup.g.dart @@ -41,7 +41,7 @@ final class UserBackupServiceProvider } } -String _$userBackupServiceHash() => r'358e4c58703b14cff767184a4f658f7eac0454f6'; +String _$userBackupServiceHash() => r'cbeffa04bb52d3c7d50a2eb38678750f2a0362cc'; abstract class _$UserBackupService extends $Notifier { void build(); diff --git a/app/lib/features/web_feed/utils/feed_parser.dart b/app/lib/features/web_feed/utils/feed_parser.dart index ee96584a..5a5454fa 100644 --- a/app/lib/features/web_feed/utils/feed_parser.dart +++ b/app/lib/features/web_feed/utils/feed_parser.dart @@ -92,7 +92,7 @@ class FeedParser { tags: tags, ); default: - throw Exception(); + throw Exception('Unknown feed type in readGeneralData: ${_feed.runtimeType}'); } } @@ -209,7 +209,7 @@ class FeedParser { ); }).toList(); default: - throw Exception(); + throw Exception('Unknown feed type in readArticles: ${_feed.runtimeType}'); } } } diff --git a/app/lib/main.dart b/app/lib/main.dart index b584735e..b985d071 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -24,6 +24,7 @@ import 'package:country_codes/country_codes.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart' show GeckoBrowserService, GeckoLoggingService, LogLevel; @@ -101,12 +102,20 @@ class _MainWidget extends HookConsumerWidget { .read(engineSettingsRepositoryProvider.notifier) .fetchSettings(); - await GeckoBrowserService().initialize( - filesystem.relativeProfilePath, - kDebugMode ? LogLevel.debug : LogLevel.warn, - engineSettings.contentBlocking, - engineSettings.addonCollection, - ); + try { + await GeckoBrowserService().initialize( + filesystem.relativeProfilePath, + kDebugMode ? LogLevel.debug : LogLevel.warn, + engineSettings.contentBlocking, + engineSettings.addonCollection, + ); + } on PlatformException catch (e, s) { + logger.e('Platform exception during Gecko initialization', error: e, stackTrace: s); + rethrow; + } catch (e, s) { + logger.e('Failed to initialize Gecko browser service', error: e, stackTrace: s); + rethrow; + } await ref.read(appInitializationServiceProvider.notifier).initialize(); diff --git a/app/lib/utils/ui_helper.dart b/app/lib/utils/ui_helper.dart index 960cd9f5..d441ea25 100644 --- a/app/lib/utils/ui_helper.dart +++ b/app/lib/utils/ui_helper.dart @@ -20,6 +20,7 @@ import 'package:flutter/material.dart'; import 'package:nullability/nullability.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:weblibre/core/logger.dart'; import 'package:weblibre/utils/clipboard.dart'; /// Creates a floating snackbar. @@ -160,7 +161,8 @@ Future launchUrlFeedback( showErrorMessage(context, 'Could not launch URL ($url)'); } } - } catch (e) { + } catch (e, s) { + logger.e('Failed to launch URL: $url', error: e, stackTrace: s); if (context.mounted) { showErrorMessage(context, 'Could not launch URL ($url)'); } diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_container_proxy.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_container_proxy.dart index bc0885e4..3667efd3 100644 --- a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_container_proxy.dart +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_container_proxy.dart @@ -5,6 +5,7 @@ */ import 'dart:async'; +import 'dart:developer' as developer; import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart'; @@ -32,7 +33,13 @@ class GeckoContainerProxyService { return await _apiInstance.healthcheck().timeout( const Duration(milliseconds: 250), ); - } catch (_) { + } catch (e, s) { + developer.log( + 'Container proxy healthcheck failed', + error: e, + stackTrace: s, + name: 'GeckoContainerProxyService', + ); return Future.value(false); } } diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart index 22438ac6..ad523bc4 100644 --- a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_history.dart @@ -50,7 +50,7 @@ class GeckoHistoryService { case VisitType.download: return _api.deleteDownload(info.contentId!); case VisitType.bookmark: - throw UnimplementedError(); + throw UnimplementedError('VisitType.bookmark deletion not implemented'); } } diff --git a/packages/flutter_mozilla_components/lib/src/geckoview_widget.dart b/packages/flutter_mozilla_components/lib/src/geckoview_widget.dart index 2fa21d2c..057662f4 100644 --- a/packages/flutter_mozilla_components/lib/src/geckoview_widget.dart +++ b/packages/flutter_mozilla_components/lib/src/geckoview_widget.dart @@ -5,6 +5,7 @@ */ import 'dart:async'; +import 'dart:developer' as developer; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -66,7 +67,7 @@ class _GeckoViewState extends State { final result = await browserService.showNativeFragment(); if (result) { - debugPrint('Fragment ATTACHED after $attempt tries'); + developer.log('Fragment ATTACHED after $attempt tries', name: 'GeckoView'); return true; } @@ -75,7 +76,7 @@ class _GeckoViewState extends State { } } - debugPrint('Fragment FAILED after $maxRetries tries'); + developer.log('Fragment FAILED after $maxRetries tries', name: 'GeckoView', level: 900); return false; }