diff --git a/.gitignore b/.gitignore index 7ee12cf5..8ec6a229 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ build/ pubspec.lock CLAUDE.md AGENTS.md +plans/ diff --git a/app/lib/features/geckoview/domain/providers.g.dart b/app/lib/features/geckoview/domain/providers.g.dart index 3349c874..142176d3 100644 --- a/app/lib/features/geckoview/domain/providers.g.dart +++ b/app/lib/features/geckoview/domain/providers.g.dart @@ -55,7 +55,7 @@ final class SelectionActionServiceProvider } String _$selectionActionServiceHash() => - r'75701bb0be3302b461d296a7b0b28e3a30a9d346'; + r'4ba617f9edb4c2ba1cb5d9e4bbc4e5eec6feecba'; @ProviderFor(eventService) final eventServiceProvider = EventServiceProvider._(); 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 4c5eff1e..498f9927 100644 --- a/app/lib/features/geckoview/domain/providers/tab_state.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_state.g.dart @@ -258,7 +258,7 @@ final class IsTabTunneledProvider } } -String _$isTabTunneledHash() => r'7265f5e6f32056846d3df38f48476d10c3a70bac'; +String _$isTabTunneledHash() => r'b11134b33ad0c98ffddd14afc2c790fb65735e93'; final class IsTabTunneledFamily extends $Family with $FunctionalFamilyOverride, String?> { @@ -358,7 +358,7 @@ final class SelectedTabTypeProvider } } -String _$selectedTabTypeHash() => r'fe14b5c9f81d8f5859ae9d758e440c42908e8a54'; +String _$selectedTabTypeHash() => r'4cf99c9175357a7835fc3c4eff29a9f328931e4f'; @ProviderFor(selectedTabContainerId) final selectedTabContainerIdProvider = SelectedTabContainerIdProvider._(); diff --git a/app/lib/features/geckoview/domain/repositories/tab.g.dart b/app/lib/features/geckoview/domain/repositories/tab.g.dart index 5996d0fd..63a6ee93 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'a6953b50e4b9d0e7e297a058872b9ad1c7d55c1a'; +String _$tabRepositoryHash() => r'1c866a1f5b1872ba07ebac82ff92455a7af316a3'; abstract class _$TabRepository extends $Notifier { void build(); diff --git a/app/lib/features/geckoview/features/browser/domain/providers.dart b/app/lib/features/geckoview/features/browser/domain/providers.dart index a66417be..4f2894c9 100644 --- a/app/lib/features/geckoview/features/browser/domain/providers.dart +++ b/app/lib/features/geckoview/features/browser/domain/providers.dart @@ -27,8 +27,10 @@ import 'package:weblibre/features/bangs/data/models/bang_data.dart'; import 'package:weblibre/features/bangs/data/models/bang_key.dart'; import 'package:weblibre/features/bangs/domain/repositories/data.dart'; import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart'; +import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_list.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; +import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart'; import 'package:weblibre/features/geckoview/features/search/domain/entities/tab_preview.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/entities/container_filter.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_entity.dart'; @@ -37,6 +39,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart' import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/gecko_inference.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart'; +import 'package:weblibre/features/user/data/models/general_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; part 'providers.g.dart'; @@ -208,6 +211,82 @@ selectedContainerTabStatesWithContainer(Ref ref) { ]); } +@Riverpod() +EquatableValue> quickTabSwitcherTabStates( + Ref ref, + QuickTabSwitcherMode mode, +) { + final selectedTabId = ref.watch(selectedTabProvider); + + final tabStates = switch (mode) { + QuickTabSwitcherMode.lastUsedTabs => ref.watch(fifoTabStatesProvider).value, + QuickTabSwitcherMode.containerTabs => + ref.watch(selectedContainerTabStatesWithContainerProvider).value, + }; + + return EquatableValue( + tabStates.where((state) => state.$1.id != selectedTabId).toList(), + ); +} + +@Riverpod() +Future> quickTabSwitcherHistorySuggestions( + Ref ref, + QuickTabSwitcherMode mode, +) async { + final showHistorySuggestions = ref.watch( + generalSettingsWithDefaultsProvider.select( + (settings) => settings.quickTabSwitcherShowHistorySuggestions, + ), + ); + + if (!showHistorySuggestions) { + return []; + } + + final hasTabStates = ref.watch( + quickTabSwitcherTabStatesProvider( + mode, + ).select((value) => value.value.isNotEmpty), + ); + if (hasTabStates) { + return []; + } + + return ref + .read(historyRepositoryProvider.notifier) + .getVisitsPaginated(count: 25); +} + +@Riverpod() +AsyncValue quickTabSwitcherHasResults( + Ref ref, + QuickTabSwitcherMode mode, +) { + final showQuickTabSwitcherBar = ref.watch( + generalSettingsWithDefaultsProvider.select( + (settings) => settings.tabBarShowQuickTabSwitcherBar, + ), + ); + if (!showQuickTabSwitcherBar) { + return const AsyncValue.data(false); + } + + final hasResults = ref.watch( + quickTabSwitcherTabStatesProvider( + mode, + ).select((value) => value.value.isNotEmpty), + ); + + if (hasResults) { + return const AsyncValue.data(true); + } + + return ref + .watch(quickTabSwitcherHistorySuggestionsProvider(mode)) + .whenData((visits) => visits.isNotEmpty); +} + @Riverpod() EquatableValue> suggestedTabEntities( Ref ref, diff --git a/app/lib/features/geckoview/features/browser/domain/providers.g.dart b/app/lib/features/geckoview/features/browser/domain/providers.g.dart index c9beceee..d39140ed 100644 --- a/app/lib/features/geckoview/features/browser/domain/providers.g.dart +++ b/app/lib/features/geckoview/features/browser/domain/providers.g.dart @@ -489,6 +489,267 @@ final class SelectedContainerTabStatesWithContainerProvider String _$selectedContainerTabStatesWithContainerHash() => r'2fd5e12595b3aced1e235c9626073c34655d57fa'; +@ProviderFor(quickTabSwitcherTabStates) +final quickTabSwitcherTabStatesProvider = QuickTabSwitcherTabStatesFamily._(); + +final class QuickTabSwitcherTabStatesProvider + extends + $FunctionalProvider< + EquatableValue>, + EquatableValue>, + EquatableValue> + > + with $Provider>> { + QuickTabSwitcherTabStatesProvider._({ + required QuickTabSwitcherTabStatesFamily super.from, + required QuickTabSwitcherMode super.argument, + }) : super( + retry: null, + name: r'quickTabSwitcherTabStatesProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$quickTabSwitcherTabStatesHash(); + + @override + String toString() { + return r'quickTabSwitcherTabStatesProvider' + '' + '($argument)'; + } + + @$internal + @override + $ProviderElement>> $createElement( + $ProviderPointer pointer, + ) => $ProviderElement(pointer); + + @override + EquatableValue> create(Ref ref) { + final argument = this.argument as QuickTabSwitcherMode; + return quickTabSwitcherTabStates(ref, argument); + } + + /// {@macro riverpod.override_with_value} + Override overrideWithValue( + EquatableValue> value, + ) { + return $ProviderOverride( + origin: this, + providerOverride: + $SyncValueProvider>>( + value, + ), + ); + } + + @override + bool operator ==(Object other) { + return other is QuickTabSwitcherTabStatesProvider && + other.argument == argument; + } + + @override + int get hashCode { + return argument.hashCode; + } +} + +String _$quickTabSwitcherTabStatesHash() => + r'db82bf9e338c94768b0531aeaffb152ff726f81f'; + +final class QuickTabSwitcherTabStatesFamily extends $Family + with + $FunctionalFamilyOverride< + EquatableValue>, + QuickTabSwitcherMode + > { + QuickTabSwitcherTabStatesFamily._() + : super( + retry: null, + name: r'quickTabSwitcherTabStatesProvider', + dependencies: null, + $allTransitiveDependencies: null, + isAutoDispose: true, + ); + + QuickTabSwitcherTabStatesProvider call(QuickTabSwitcherMode mode) => + QuickTabSwitcherTabStatesProvider._(argument: mode, from: this); + + @override + String toString() => r'quickTabSwitcherTabStatesProvider'; +} + +@ProviderFor(quickTabSwitcherHistorySuggestions) +final quickTabSwitcherHistorySuggestionsProvider = + QuickTabSwitcherHistorySuggestionsFamily._(); + +final class QuickTabSwitcherHistorySuggestionsProvider + extends + $FunctionalProvider< + AsyncValue>, + List, + FutureOr> + > + with $FutureModifier>, $FutureProvider> { + QuickTabSwitcherHistorySuggestionsProvider._({ + required QuickTabSwitcherHistorySuggestionsFamily super.from, + required QuickTabSwitcherMode super.argument, + }) : super( + retry: null, + name: r'quickTabSwitcherHistorySuggestionsProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => + _$quickTabSwitcherHistorySuggestionsHash(); + + @override + String toString() { + return r'quickTabSwitcherHistorySuggestionsProvider' + '' + '($argument)'; + } + + @$internal + @override + $FutureProviderElement> $createElement( + $ProviderPointer pointer, + ) => $FutureProviderElement(pointer); + + @override + FutureOr> create(Ref ref) { + final argument = this.argument as QuickTabSwitcherMode; + return quickTabSwitcherHistorySuggestions(ref, argument); + } + + @override + bool operator ==(Object other) { + return other is QuickTabSwitcherHistorySuggestionsProvider && + other.argument == argument; + } + + @override + int get hashCode { + return argument.hashCode; + } +} + +String _$quickTabSwitcherHistorySuggestionsHash() => + r'3446741dfedf6fda9ab61421c1b74370c7f43f5b'; + +final class QuickTabSwitcherHistorySuggestionsFamily extends $Family + with + $FunctionalFamilyOverride< + FutureOr>, + QuickTabSwitcherMode + > { + QuickTabSwitcherHistorySuggestionsFamily._() + : super( + retry: null, + name: r'quickTabSwitcherHistorySuggestionsProvider', + dependencies: null, + $allTransitiveDependencies: null, + isAutoDispose: true, + ); + + QuickTabSwitcherHistorySuggestionsProvider call(QuickTabSwitcherMode mode) => + QuickTabSwitcherHistorySuggestionsProvider._(argument: mode, from: this); + + @override + String toString() => r'quickTabSwitcherHistorySuggestionsProvider'; +} + +@ProviderFor(quickTabSwitcherHasResults) +final quickTabSwitcherHasResultsProvider = QuickTabSwitcherHasResultsFamily._(); + +final class QuickTabSwitcherHasResultsProvider + extends + $FunctionalProvider< + AsyncValue, + AsyncValue, + AsyncValue + > + with $Provider> { + QuickTabSwitcherHasResultsProvider._({ + required QuickTabSwitcherHasResultsFamily super.from, + required QuickTabSwitcherMode super.argument, + }) : super( + retry: null, + name: r'quickTabSwitcherHasResultsProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$quickTabSwitcherHasResultsHash(); + + @override + String toString() { + return r'quickTabSwitcherHasResultsProvider' + '' + '($argument)'; + } + + @$internal + @override + $ProviderElement> $createElement($ProviderPointer pointer) => + $ProviderElement(pointer); + + @override + AsyncValue create(Ref ref) { + final argument = this.argument as QuickTabSwitcherMode; + return quickTabSwitcherHasResults(ref, argument); + } + + /// {@macro riverpod.override_with_value} + Override overrideWithValue(AsyncValue value) { + return $ProviderOverride( + origin: this, + providerOverride: $SyncValueProvider>(value), + ); + } + + @override + bool operator ==(Object other) { + return other is QuickTabSwitcherHasResultsProvider && + other.argument == argument; + } + + @override + int get hashCode { + return argument.hashCode; + } +} + +String _$quickTabSwitcherHasResultsHash() => + r'bcbddfefe7f5eb2c5d8c7c1925fe593a857b477b'; + +final class QuickTabSwitcherHasResultsFamily extends $Family + with $FunctionalFamilyOverride, QuickTabSwitcherMode> { + QuickTabSwitcherHasResultsFamily._() + : super( + retry: null, + name: r'quickTabSwitcherHasResultsProvider', + dependencies: null, + $allTransitiveDependencies: null, + isAutoDispose: true, + ); + + QuickTabSwitcherHasResultsProvider call(QuickTabSwitcherMode mode) => + QuickTabSwitcherHasResultsProvider._(argument: mode, from: this); + + @override + String toString() => r'quickTabSwitcherHasResultsProvider'; +} + @ProviderFor(suggestedTabEntities) final suggestedTabEntitiesProvider = SuggestedTabEntitiesFamily._(); diff --git a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart index 2cd4cedc..6957b4de 100644 --- a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart +++ b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart @@ -42,7 +42,7 @@ final class ProxySettingsReplicationProvider } String _$proxySettingsReplicationHash() => - r'79eca77aa476ed46cfe342e52926ea1cf956dc70'; + r'7f47a561441cc2d594e9380d62dcc31f4c1059d3'; abstract class _$ProxySettingsReplication extends $Notifier { void build(); diff --git a/app/lib/features/geckoview/features/browser/presentation/providers/site_settings_badge_provider.g.dart b/app/lib/features/geckoview/features/browser/presentation/providers/site_settings_badge_provider.g.dart index 3bd53bfe..a88b8661 100644 --- a/app/lib/features/geckoview/features/browser/presentation/providers/site_settings_badge_provider.g.dart +++ b/app/lib/features/geckoview/features/browser/presentation/providers/site_settings_badge_provider.g.dart @@ -48,4 +48,4 @@ final class ShowSiteSettingsBadgeProvider } String _$showSiteSettingsBadgeHash() => - r'f44282c62556c39d439c499519a2a9861082cfcb'; + r'c68e3b37b6f25e02779123b3f642a58dc98ba3a7'; diff --git a/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart index a286649e..bef8cd77 100644 --- a/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart +++ b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart @@ -39,6 +39,7 @@ import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/entities/sheet.dart'; +import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/controllers/tab_view_controllers.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/controllers/toolbar_visibility.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/dialogs/keep_tab_dialog.dart'; @@ -274,6 +275,16 @@ class BrowserScreen extends HookConsumerWidget { (value) => value.tabBarShowQuickTabSwitcherBar, ), ); + final quickTabSwitcherMode = ref.watch( + generalSettingsWithDefaultsProvider.select( + (value) => value.quickTabSwitcherMode, + ), + ); + final quickTabSwitcherHasResults = ref.watch( + quickTabSwitcherHasResultsProvider(quickTabSwitcherMode), + ); + final displayQuickTabSwitcherBar = + showQuickTabSwitcherBar && (quickTabSwitcherHasResults.value ?? false); final autoHideTabBar = ref.watch( generalSettingsWithDefaultsProvider.select( @@ -373,7 +384,7 @@ class BrowserScreen extends HookConsumerWidget { final bottomAppBarContentSize = BrowserBottomAppBar( showMainToolbar: tabBarPosition == TabBarPosition.bottom, showContextualToolbar: showContextualToolbar, - showQuickTabSwitcherBar: showQuickTabSwitcherBar, + showQuickTabSwitcherBar: displayQuickTabSwitcherBar, displayedSheet: displayedSheet, ).preferredSize; // Total height includes safe area padding @@ -391,7 +402,7 @@ class BrowserScreen extends HookConsumerWidget { final topAppBarContentSize = BrowserTopAppBar( showMainToolbar: tabBarPosition == TabBarPosition.top, showContextualToolbar: showContextualToolbar, - showQuickTabSwitcherBar: showQuickTabSwitcherBar, + showQuickTabSwitcherBar: displayQuickTabSwitcherBar, ).preferredSize; final topAppBarTotalHeight = topAppBarContentSize.height + topSafeArea; @@ -608,7 +619,7 @@ class BrowserScreen extends HookConsumerWidget { tabBarPosition: TabBarPosition.bottom, showMainToolbar: tabBarPosition == TabBarPosition.bottom, showContextualToolbar: showContextualToolbar, - showQuickTabSwitcherBar: showQuickTabSwitcherBar, + showQuickTabSwitcherBar: displayQuickTabSwitcherBar, // Only subscribe to scroll events when this is the active position pointerMoveEvents: tabBarPosition == TabBarPosition.bottom ? pointerMoveEventsController.stream @@ -631,7 +642,7 @@ class BrowserScreen extends HookConsumerWidget { tabBarPosition: TabBarPosition.top, showMainToolbar: true, showContextualToolbar: showContextualToolbar, - showQuickTabSwitcherBar: showQuickTabSwitcherBar, + showQuickTabSwitcherBar: displayQuickTabSwitcherBar, pointerMoveEvents: pointerMoveEventsController.stream, ), ), diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart index 783ff81c..005d4931 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart @@ -47,7 +47,6 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_menu.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/toolbar_button.dart'; -import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart'; import 'package:weblibre/features/geckoview/features/readerview/presentation/controllers/readerable.dart'; import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_mode.dart'; @@ -55,7 +54,6 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart' import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart'; import 'package:weblibre/features/user/data/models/general_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; -import 'package:weblibre/presentation/hooks/cached_future.dart'; import 'package:weblibre/presentation/hooks/menu_controller.dart'; import 'package:weblibre/presentation/icons/weblibre_icons.dart'; import 'package:weblibre/presentation/widgets/selectable_chips.dart'; @@ -487,29 +485,49 @@ class QuickTabSwitcher extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final appColors = AppColors.of(context); - final selectedTabId = ref.watch(selectedTabProvider); final showTitles = ref.watch( generalSettingsWithDefaultsProvider.select( (s) => s.quickTabSwitcherShowTitles, ), ); + final tabStates = ref.watch( + quickTabSwitcherTabStatesProvider(quickTabSwitcherMode), + ); + final historySuggestions = ref + .watch(quickTabSwitcherHistorySuggestionsProvider(quickTabSwitcherMode)) + .value; + final availableItems = tabStates.value + .map<_QuickTabItem>( + (state) => ( + id: state.$1.id, + title: state.$1.titleOrAuthority, + tabMode: state.$1.tabMode, + isHistory: false, + url: state.$1.url, + color: state.$2?.color, + tabState: state.$1, + ), + ) + .followedBy( + (historySuggestions ?? []).map<_QuickTabItem>((state) { + final url = Uri.parse(state.url); - final tabStates = (switch (quickTabSwitcherMode) { - QuickTabSwitcherMode.lastUsedTabs => ref.watch(fifoTabStatesProvider), - QuickTabSwitcherMode.containerTabs => ref.watch( - selectedContainerTabStatesWithContainerProvider, - ), - }).value.where((state) => state.$1.id != selectedTabId).toList(); + return ( + id: state.url, + title: state.title ?? url.authority, + tabMode: TabMode.regular, + isHistory: true, + url: url, + color: null, + tabState: null, + ); + }), + ) + .toList(); - final historyAsync = useCachedFuture(() { - if (tabStates.isEmpty) { - return ref - .read(historyRepositoryProvider.notifier) - .getVisitsPaginated(count: 25); - } - - return Future.value([]); - }, [tabStates.isEmpty]); + if (availableItems.isEmpty) { + return const SizedBox.shrink(); + } final chipScrollController = useScrollController(); @@ -618,33 +636,7 @@ class QuickTabSwitcher extends HookConsumerWidget { }, ); }, - availableItems: tabStates - .map<_QuickTabItem>( - (state) => ( - id: state.$1.id, - title: state.$1.titleOrAuthority, - tabMode: state.$1.tabMode, - isHistory: false, - url: state.$1.url, - color: state.$2?.color, - tabState: state.$1, - ), - ) - .followedBy( - (historyAsync.data ?? []).map<_QuickTabItem>((state) { - final url = Uri.parse(state.url); - - return ( - id: state.url, - title: state.title ?? url.authority, - tabMode: TabMode.regular, - isHistory: true, - url: url, - color: null, - tabState: null, - ); - }), - ), + availableItems: availableItems, ), ), ); diff --git a/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart b/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart index 7b8b3705..c5c4e408 100644 --- a/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart +++ b/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart @@ -31,7 +31,6 @@ import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_sour import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/models/tab_query_result.dart'; -@DriftAccessor() class SyncTabsResult { final Set deletedIsolationContextIds; final int deletedCount; @@ -42,6 +41,7 @@ class SyncTabsResult { }); } +@DriftAccessor() class TabDao extends DatabaseAccessor with $TabDaoMixin { final _undoHistory = {}; Timer? _clearHistoryTimer; diff --git a/app/lib/features/settings/presentation/screens/appearance_display_settings.dart b/app/lib/features/settings/presentation/screens/appearance_display_settings.dart index 437bc408..89c1e9b2 100644 --- a/app/lib/features/settings/presentation/screens/appearance_display_settings.dart +++ b/app/lib/features/settings/presentation/screens/appearance_display_settings.dart @@ -82,6 +82,7 @@ class _TabBarLayoutSection extends StatelessWidget { _TabListShowFaviconsTile(), _ShowQuickTabSwitcherBarTile(), _QuickTabSwitcherModeSection(), + _QuickTabSwitcherHistorySuggestionsTile(), _QuickTabSwitcherShowTitlesTile(), ], ); @@ -125,6 +126,43 @@ class _QuickTabSwitcherShowTitlesTile extends HookConsumerWidget { } } +class _QuickTabSwitcherHistorySuggestionsTile extends HookConsumerWidget { + const _QuickTabSwitcherHistorySuggestionsTile(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final showHistorySuggestions = ref.watch( + generalSettingsWithDefaultsProvider.select( + (s) => s.quickTabSwitcherShowHistorySuggestions, + ), + ); + final tabBarShowQuickTabSwitcherBar = ref.watch( + generalSettingsWithDefaultsProvider.select( + (s) => s.tabBarShowQuickTabSwitcherBar, + ), + ); + + return SwitchListTile.adaptive( + title: const Text('History Fallback in Quick Tab Switcher'), + subtitle: const Text( + 'Use browsing history suggestions when no tab chips are available', + ), + secondary: const Icon(MdiIcons.history), + value: showHistorySuggestions, + onChanged: tabBarShowQuickTabSwitcherBar + ? (value) async { + await ref + .read(saveGeneralSettingsControllerProvider.notifier) + .save( + (currentSettings) => currentSettings.copyWith + .quickTabSwitcherShowHistorySuggestions(value), + ); + } + : null, + ); + } +} + class _GesturesSection extends StatelessWidget { const _GesturesSection(); diff --git a/app/lib/features/user/data/models/general_settings.dart b/app/lib/features/user/data/models/general_settings.dart index a2e32ee3..165b122c 100644 --- a/app/lib/features/user/data/models/general_settings.dart +++ b/app/lib/features/user/data/models/general_settings.dart @@ -88,6 +88,7 @@ class GeneralSettings with FastEquatable { final bool allowClipboardAccess; final bool tabListShowFavicons; final bool quickTabSwitcherShowTitles; + final bool quickTabSwitcherShowHistorySuggestions; final bool drawerGestureEnabled; final String syncServerOverride; final String syncTokenServerOverride; @@ -131,6 +132,7 @@ class GeneralSettings with FastEquatable { required this.allowClipboardAccess, required this.tabListShowFavicons, required this.quickTabSwitcherShowTitles, + required this.quickTabSwitcherShowHistorySuggestions, required this.drawerGestureEnabled, required this.syncServerOverride, required this.syncTokenServerOverride, @@ -175,6 +177,7 @@ class GeneralSettings with FastEquatable { bool? allowClipboardAccess, bool? tabListShowFavicons, bool? quickTabSwitcherShowTitles, + bool? quickTabSwitcherShowHistorySuggestions, bool? drawerGestureEnabled, String? syncServerOverride, String? syncTokenServerOverride, @@ -220,6 +223,8 @@ class GeneralSettings with FastEquatable { allowClipboardAccess = allowClipboardAccess ?? true, tabListShowFavicons = tabListShowFavicons ?? false, quickTabSwitcherShowTitles = quickTabSwitcherShowTitles ?? true, + quickTabSwitcherShowHistorySuggestions = + quickTabSwitcherShowHistorySuggestions ?? true, drawerGestureEnabled = drawerGestureEnabled ?? false, syncServerOverride = syncServerOverride ?? '', syncTokenServerOverride = syncTokenServerOverride ?? '', @@ -273,6 +278,7 @@ class GeneralSettings with FastEquatable { allowClipboardAccess, tabListShowFavicons, quickTabSwitcherShowTitles, + quickTabSwitcherShowHistorySuggestions, drawerGestureEnabled, syncServerOverride, syncTokenServerOverride, diff --git a/app/lib/features/user/data/models/general_settings.g.dart b/app/lib/features/user/data/models/general_settings.g.dart index a69354c5..9aa712b7 100644 --- a/app/lib/features/user/data/models/general_settings.g.dart +++ b/app/lib/features/user/data/models/general_settings.g.dart @@ -75,6 +75,10 @@ abstract class _$GeneralSettingsCWProxy { GeneralSettings quickTabSwitcherShowTitles(bool quickTabSwitcherShowTitles); + GeneralSettings quickTabSwitcherShowHistorySuggestions( + bool quickTabSwitcherShowHistorySuggestions, + ); + GeneralSettings drawerGestureEnabled(bool drawerGestureEnabled); GeneralSettings syncServerOverride(String syncServerOverride); @@ -139,6 +143,7 @@ abstract class _$GeneralSettingsCWProxy { bool allowClipboardAccess, bool tabListShowFavicons, bool quickTabSwitcherShowTitles, + bool quickTabSwitcherShowHistorySuggestions, bool drawerGestureEnabled, String syncServerOverride, String syncTokenServerOverride, @@ -279,6 +284,14 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { GeneralSettings quickTabSwitcherShowTitles(bool quickTabSwitcherShowTitles) => call(quickTabSwitcherShowTitles: quickTabSwitcherShowTitles); + @override + GeneralSettings quickTabSwitcherShowHistorySuggestions( + bool quickTabSwitcherShowHistorySuggestions, + ) => call( + quickTabSwitcherShowHistorySuggestions: + quickTabSwitcherShowHistorySuggestions, + ); + @override GeneralSettings drawerGestureEnabled(bool drawerGestureEnabled) => call(drawerGestureEnabled: drawerGestureEnabled); @@ -370,6 +383,8 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { Object? allowClipboardAccess = const $CopyWithPlaceholder(), Object? tabListShowFavicons = const $CopyWithPlaceholder(), Object? quickTabSwitcherShowTitles = const $CopyWithPlaceholder(), + Object? quickTabSwitcherShowHistorySuggestions = + const $CopyWithPlaceholder(), Object? drawerGestureEnabled = const $CopyWithPlaceholder(), Object? syncServerOverride = const $CopyWithPlaceholder(), Object? syncTokenServerOverride = const $CopyWithPlaceholder(), @@ -549,6 +564,13 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { ? _value.quickTabSwitcherShowTitles // ignore: cast_nullable_to_non_nullable : quickTabSwitcherShowTitles as bool, + quickTabSwitcherShowHistorySuggestions: + quickTabSwitcherShowHistorySuggestions == + const $CopyWithPlaceholder() || + quickTabSwitcherShowHistorySuggestions == null + ? _value.quickTabSwitcherShowHistorySuggestions + // ignore: cast_nullable_to_non_nullable + : quickTabSwitcherShowHistorySuggestions as bool, drawerGestureEnabled: drawerGestureEnabled == const $CopyWithPlaceholder() || drawerGestureEnabled == null @@ -704,6 +726,8 @@ GeneralSettings _$GeneralSettingsFromJson( allowClipboardAccess: json['allowClipboardAccess'] as bool?, tabListShowFavicons: json['tabListShowFavicons'] as bool?, quickTabSwitcherShowTitles: json['quickTabSwitcherShowTitles'] as bool?, + quickTabSwitcherShowHistorySuggestions: + json['quickTabSwitcherShowHistorySuggestions'] as bool?, drawerGestureEnabled: json['drawerGestureEnabled'] as bool?, syncServerOverride: json['syncServerOverride'] as String?, syncTokenServerOverride: json['syncTokenServerOverride'] as String?, @@ -761,6 +785,8 @@ Map _$GeneralSettingsToJson( 'allowClipboardAccess': instance.allowClipboardAccess, 'tabListShowFavicons': instance.tabListShowFavicons, 'quickTabSwitcherShowTitles': instance.quickTabSwitcherShowTitles, + 'quickTabSwitcherShowHistorySuggestions': + instance.quickTabSwitcherShowHistorySuggestions, 'drawerGestureEnabled': instance.drawerGestureEnabled, 'syncServerOverride': instance.syncServerOverride, 'syncTokenServerOverride': instance.syncTokenServerOverride, diff --git a/app/lib/features/user/domain/repositories/general_settings.dart b/app/lib/features/user/domain/repositories/general_settings.dart index 3be83f14..99bbd7bf 100644 --- a/app/lib/features/user/domain/repositories/general_settings.dart +++ b/app/lib/features/user/domain/repositories/general_settings.dart @@ -151,6 +151,11 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository { ), 'quickTabSwitcherShowTitles': settings['quickTabSwitcherShowTitles'] ?.readAs(DriftSqlType.bool, db.typeMapping), + 'quickTabSwitcherShowHistorySuggestions': + settings['quickTabSwitcherShowHistorySuggestions']?.readAs( + DriftSqlType.bool, + db.typeMapping, + ), 'drawerGestureEnabled': settings['drawerGestureEnabled']?.readAs( DriftSqlType.bool, db.typeMapping, diff --git a/app/lib/features/user/domain/repositories/general_settings.g.dart b/app/lib/features/user/domain/repositories/general_settings.g.dart index 470fb1f3..87525066 100644 --- a/app/lib/features/user/domain/repositories/general_settings.g.dart +++ b/app/lib/features/user/domain/repositories/general_settings.g.dart @@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider } String _$generalSettingsRepositoryHash() => - r'83aed230cdc33b3e15b91fdb433427faaa8c7cc7'; + r'5fcb1b28918a6c7bb23f72681fdec8bee77e49a5'; abstract class _$GeneralSettingsRepository extends $StreamNotifier { diff --git a/app/lib/presentation/controllers/website_title.g.dart b/app/lib/presentation/controllers/website_title.g.dart index 86fbff03..19758951 100644 --- a/app/lib/presentation/controllers/website_title.g.dart +++ b/app/lib/presentation/controllers/website_title.g.dart @@ -162,7 +162,7 @@ final class PageInfoProvider } } -String _$pageInfoHash() => r'c8b7a44b675742436999941b526e9b268ebd139e'; +String _$pageInfoHash() => r'9a379657c8a3f353aba1dfb0f66b9100ce494fc5'; final class PageInfoFamily extends $Family with