From f95331c654013d60fd1e30d420931738fbdb5150 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Fri, 25 Apr 2025 20:41:08 +0200 Subject: [PATCH] support private tabs --- app/lib/core/routing/routes.browser.dart | 15 ++- app/lib/core/routing/routes.g.dart | 18 ++- .../bangs/presentation/screens/list.dart | 2 +- .../presentation/widgets/site_search.dart | 18 ++- .../features/geckoview/domain/providers.dart | 9 +- .../geckoview/domain/providers.g.dart | 2 +- .../presentation/dialogs/web_page_dialog.dart | 25 ++++ .../browser_modules/bottom_app_bar.dart | 19 ++- .../widgets/browser_modules/browser_view.dart | 2 +- .../widgets/sheets/view_tabs.dart | 5 +- .../presentation/widgets/tab_preview.dart | 29 +++-- .../candidates/open_image_new_tab.dart | 7 +- .../presentation/candidates/open_new_tab.dart | 7 +- .../search/presentation/screens/search.dart | 119 ++++++++++++------ .../search_modules/history_suggestions.dart | 9 +- 15 files changed, 212 insertions(+), 74 deletions(-) diff --git a/app/lib/core/routing/routes.browser.dart b/app/lib/core/routing/routes.browser.dart index 604adcf8..f214ff23 100644 --- a/app/lib/core/routing/routes.browser.dart +++ b/app/lib/core/routing/routes.browser.dart @@ -5,7 +5,10 @@ part of 'routes.dart'; path: '/', routes: [ TypedGoRoute(name: 'WebPageRoute', path: 'page/:url'), - TypedGoRoute(name: 'SearchRoute', path: 'search/:searchText'), + TypedGoRoute( + name: 'SearchRoute', + path: 'search/:tabType/:searchText', + ), TypedGoRoute(name: 'TorProxyRoute', path: 'tor_proxy'), TypedGoRoute( name: 'ContextMenuRoute', @@ -50,17 +53,25 @@ class WebPageRoute extends GoRouteData { } } +enum TabType { regular, private } + class SearchRoute extends GoRouteData { static const String emptySearchText = ' '; + final TabType tabType; + //This should be nullable but isnt allowed by go_router final String searchText; - const SearchRoute({this.searchText = SearchRoute.emptySearchText}); + const SearchRoute({ + required this.tabType, + this.searchText = SearchRoute.emptySearchText, + }); @override Widget build(BuildContext context, GoRouterState state) { return SearchScreen( + tabType: tabType, initialSearchText: (searchText.isEmpty || searchText == emptySearchText) ? null diff --git a/app/lib/core/routing/routes.g.dart b/app/lib/core/routing/routes.g.dart index de900400..ae80bd29 100644 --- a/app/lib/core/routing/routes.g.dart +++ b/app/lib/core/routing/routes.g.dart @@ -214,7 +214,7 @@ RouteBase get $browserRoute => GoRouteData.$route( factory: $WebPageRouteExtension._fromState, ), GoRouteData.$route( - path: 'search/:searchText', + path: 'search/:tabType/:searchText', name: 'SearchRoute', factory: $SearchRouteExtension._fromState, @@ -292,12 +292,14 @@ extension $WebPageRouteExtension on WebPageRoute { extension $SearchRouteExtension on SearchRoute { static SearchRoute _fromState(GoRouterState state) => SearchRoute( + tabType: _$TabTypeEnumMap._$fromName(state.pathParameters['tabType']!)!, searchText: state.pathParameters['searchText'] ?? SearchRoute.emptySearchText, ); - String get location => - GoRouteData.$location('/search/${Uri.encodeComponent(searchText)}'); + String get location => GoRouteData.$location( + '/search/${Uri.encodeComponent(_$TabTypeEnumMap[tabType]!)}/${Uri.encodeComponent(searchText)}', + ); void go(BuildContext context) => context.go(location); @@ -309,6 +311,11 @@ extension $SearchRouteExtension on SearchRoute { void replace(BuildContext context) => context.replace(location); } +const _$TabTypeEnumMap = { + TabType.regular: 'regular', + TabType.private: 'private', +}; + extension $TorProxyRouteExtension on TorProxyRoute { static TorProxyRoute _fromState(GoRouterState state) => TorProxyRoute(); @@ -394,6 +401,11 @@ extension $ContainerEditRouteExtension on ContainerEditRoute { context.replace(location, extra: $extra); } +extension on Map { + T? _$fromName(String? value) => + entries.where((element) => element.value == value).firstOrNull?.key; +} + RouteBase get $bangCategoriesRoute => GoRouteData.$route( path: '/bangs', name: 'BangRoute', diff --git a/app/lib/features/bangs/presentation/screens/list.dart b/app/lib/features/bangs/presentation/screens/list.dart index 4023faba..305e2a87 100644 --- a/app/lib/features/bangs/presentation/screens/list.dart +++ b/app/lib/features/bangs/presentation/screens/list.dart @@ -41,7 +41,7 @@ class BangListScreen extends HookConsumerWidget { .read(selectedBangTriggerProvider().notifier) .setTrigger(bang.trigger); - const SearchRoute().go(context); + const SearchRoute(tabType: TabType.regular).go(context); }, ); }, diff --git a/app/lib/features/bangs/presentation/widgets/site_search.dart b/app/lib/features/bangs/presentation/widgets/site_search.dart index 92ff1fd1..5c762d3c 100644 --- a/app/lib/features/bangs/presentation/widgets/site_search.dart +++ b/app/lib/features/bangs/presentation/widgets/site_search.dart @@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; import 'package:lensai/features/bangs/domain/providers/search.dart'; import 'package:lensai/features/geckoview/domain/providers/tab_session.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; import 'package:lensai/features/geckoview/features/browser/domain/providers.dart'; import 'package:lensai/features/geckoview/features/search/domain/providers/search_suggestions.dart'; @@ -45,12 +46,21 @@ class SiteSearch extends HookConsumerWidget { Future submitSearch(String query) async { if (activeBang != null && (formKey.currentState?.validate() == true)) { - final searchUri = await ref - .read(bangSearchProvider.notifier) - .triggerBangSearch(activeBang, query); + final isPrivate = + ref.read(selectedTabStateProvider)?.isPrivate ?? false; + + final searchUri = activeBang.getTemplateUrl(query); + + if (!isPrivate) { + await ref + .read(bangSearchProvider.notifier) + .triggerBangSearch(activeBang, query); + } if (searchInNewTab) { - await ref.read(tabRepositoryProvider.notifier).addTab(url: searchUri); + await ref + .read(tabRepositoryProvider.notifier) + .addTab(url: searchUri, private: isPrivate); } else { await ref .read(tabSessionProvider(tabId: null).notifier) diff --git a/app/lib/features/geckoview/domain/providers.dart b/app/lib/features/geckoview/domain/providers.dart index 5f90e185..de3b40ae 100644 --- a/app/lib/features/geckoview/domain/providers.dart +++ b/app/lib/features/geckoview/domain/providers.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:lensai/core/logger.dart'; import 'package:lensai/features/bangs/domain/providers/bangs.dart'; -import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; import 'package:riverpod/riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -24,13 +24,14 @@ GeckoSelectionActionService selectionActionService(Ref ref) { ); if (defaultSearchBang != null) { - final currentTabId = ref.read(selectedTabProvider); + final currentTab = ref.read(selectedTabStateProvider); await ref .read(tabRepositoryProvider.notifier) .addTab( url: defaultSearchBang.getTemplateUrl(text), - parentId: currentTabId, + parentId: currentTab?.id, + private: currentTab?.isPrivate ?? false, ); } else { logger.e('No default search bang found'); @@ -50,7 +51,7 @@ GeckoSelectionActionService selectionActionService(Ref ref) { // } // }), ShareAction((text) async { - await Share.share(text); + await SharePlus.instance.share(ShareParams(text: text)); }), CallAction((text) async { final uri = Uri.tryParse('tel:${text.replaceAll(' ', '')}'); diff --git a/app/lib/features/geckoview/domain/providers.g.dart b/app/lib/features/geckoview/domain/providers.g.dart index 079094f3..bb2d91db 100644 --- a/app/lib/features/geckoview/domain/providers.g.dart +++ b/app/lib/features/geckoview/domain/providers.g.dart @@ -7,7 +7,7 @@ part of 'providers.dart'; // ************************************************************************** String _$selectionActionServiceHash() => - r'd907a3c5ab7efde82bb2cc1fb0409fd3fd13bb25'; + r'fc7344fa34f0e27772309303083804866336197b'; /// See also [selectionActionService]. @ProviderFor(selectionActionService) diff --git a/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart b/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart index 3787f6d0..77209b29 100644 --- a/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart +++ b/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart @@ -161,6 +161,31 @@ class WebPageDialog extends HookConsumerWidget { } }, ), + ListTile( + leading: const Icon(MdiIcons.tabUnselected), + title: const Text('Clone as private tab'), + onTap: () async { + final tabId = await ref + .read(tabRepositoryProvider.notifier) + .addTab(url: url, private: true); + + if (context.mounted) { + //save reference before pop `ref` gets disposed + final repo = ref.read( + tabRepositoryProvider.notifier, + ); + + ui_helper.showTabSwitchMessage( + context, + onSwitch: () { + repo.selectTab(tabId); + }, + ); + + context.pop(); + } + }, + ), ListTile( leading: const Icon(Icons.share), title: const Text('Share link'), 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 56f09985..d1ef0ac2 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 @@ -106,7 +106,7 @@ class BrowserBottomAppBar extends HookConsumerWidget { return child!; }, menuChildren: [ - if (selectedTabId != null) + if (selectedTabId != null) ...[ MenuItemButton( onPressed: () async { await ref @@ -116,11 +116,24 @@ class BrowserBottomAppBar extends HookConsumerWidget { leadingIcon: const Icon(Icons.close), child: const Text('Close Tab'), ), + const Divider(), + ], MenuItemButton( onPressed: () async { - await const SearchRoute().push(context); + await const SearchRoute( + tabType: TabType.private, + ).push(context); }, - leadingIcon: const Icon(Icons.add), + leadingIcon: const Icon(MdiIcons.tabUnselected), + child: const Text('Add Private Tab'), + ), + MenuItemButton( + onPressed: () async { + await const SearchRoute( + tabType: TabType.regular, + ).push(context); + }, + leadingIcon: const Icon(MdiIcons.tabPlus), child: const Text('Add Tab'), ), ], 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 8e5676a8..e247e029 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 @@ -210,7 +210,7 @@ class _BrowserViewState extends ConsumerState showSuggestNewTabMessage( context, onAdd: () async { - await const SearchRoute().push(context); + await const SearchRoute(tabType: TabType.regular).push(context); }, ); } diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart index e25b89a1..5432aa94 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_reorderable_grid_view/widgets/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/core/providers/global_drop.dart'; @@ -62,7 +63,7 @@ class _TabSheetHeader extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton.icon( - icon: const Icon(Icons.search), + icon: const Icon(MdiIcons.tabSearch), label: const Text('Search'), onPressed: () { searchMode.value = true; @@ -410,7 +411,7 @@ class ViewTabsSheetWidget extends HookConsumerWidget { ), child: FloatingActionButton.small( onPressed: () async { - await const SearchRoute().push(context); + await const SearchRoute(tabType: TabType.regular).push(context); onClose(); }, diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_preview.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_preview.dart index 1086a5fb..23470e59 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_preview.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_preview.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/geckoview/domain/entities/states/tab.dart'; import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; @@ -34,10 +35,13 @@ class TabPreview extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(16.0)), ), child: Material( - color: colorScheme.surfaceContainerHighest, - borderRadius: const BorderRadius.all(Radius.circular(16.0)), + color: + tab.isPrivate + ? const Color(0xFF25003E) + : colorScheme.surfaceContainerHighest, + borderRadius: const BorderRadius.all(Radius.circular(14.0)), child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(16.0)), + borderRadius: const BorderRadius.all(Radius.circular(14.0)), onTap: onTap, onDoubleTap: onDoubleTap, child: Column( @@ -46,11 +50,15 @@ class TabPreview extends StatelessWidget { children: [ Expanded( child: Padding( - padding: const EdgeInsets.only(left: 6.0), + padding: const EdgeInsets.only(left: 6.0, top: 2.0), child: Text( overflow: TextOverflow.ellipsis, tab.title, maxLines: 2, + style: + tab.isPrivate + ? const TextStyle(color: Colors.white) + : null, ), ), ), @@ -72,9 +80,16 @@ class TabPreview extends StatelessWidget { Expanded( child: Text( tab.url.authority, - style: Theme.of(context).textTheme.bodySmall, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: tab.isPrivate ? Colors.white : null, + ), ), ), + if (tab.isPrivate) ...[ + const SizedBox(width: 6.0), + const Icon(MdiIcons.dominoMask, color: Color(0xFF8000D7)), + ], + const SizedBox(width: 8.0), ], ), const SizedBox(height: 6), @@ -82,8 +97,8 @@ class TabPreview extends StatelessWidget { Expanded( child: ClipRRect( borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(16.0), - bottomRight: Radius.circular(16.0), + bottomLeft: Radius.circular(14.0), + bottomRight: Radius.circular(14.0), ), child: SizedBox( width: double.infinity, diff --git a/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_image_new_tab.dart b/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_image_new_tab.dart index 3016f0d8..9c83d010 100644 --- a/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_image_new_tab.dart +++ b/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_image_new_tab.dart @@ -3,7 +3,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; import 'package:lensai/features/geckoview/features/contextmenu/extensions/hit_result.dart'; import 'package:lensai/utils/ui_helper.dart'; @@ -23,14 +23,15 @@ class OpenImageInNewTab extends HookConsumerWidget { leading: const Icon(MdiIcons.tabPlus), title: const Text('Open image in new tab'), onTap: () async { - final currentTabId = ref.read(selectedTabProvider); + final currentTab = ref.read(selectedTabStateProvider); final tabId = await ref .read(tabRepositoryProvider.notifier) .addTab( url: hitResult.tryGetLink(), - parentId: currentTabId, + parentId: currentTab?.id, selectTab: false, + private: currentTab?.isPrivate ?? false, ); if (context.mounted) { diff --git a/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_new_tab.dart b/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_new_tab.dart index 9fa39425..407c94c6 100644 --- a/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_new_tab.dart +++ b/app/lib/features/geckoview/features/contextmenu/presentation/candidates/open_new_tab.dart @@ -3,7 +3,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; import 'package:lensai/features/geckoview/features/contextmenu/extensions/hit_result.dart'; import 'package:lensai/utils/ui_helper.dart'; @@ -23,14 +23,15 @@ class OpenInNewTab extends HookConsumerWidget { leading: const Icon(MdiIcons.tabPlus), title: const Text('Open in new tab'), onTap: () async { - final currentTabId = ref.read(selectedTabProvider); + final currentTab = ref.read(selectedTabStateProvider); final tabId = await ref .read(tabRepositoryProvider.notifier) .addTab( url: hitResult.tryGetLink(), - parentId: currentTabId, + parentId: currentTab?.id, selectTab: false, + private: currentTab?.isPrivate ?? false, ); if (context.mounted) { diff --git a/app/lib/features/geckoview/features/search/presentation/screens/search.dart b/app/lib/features/geckoview/features/search/presentation/screens/search.dart index 1860dd03..d8adb850 100644 --- a/app/lib/features/geckoview/features/search/presentation/screens/search.dart +++ b/app/lib/features/geckoview/features/search/presentation/screens/search.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:lensai/core/routing/routes.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/domain/providers/search.dart'; @@ -18,13 +20,17 @@ import 'package:lensai/utils/uri_parser.dart' as uri_parser; class SearchScreen extends HookConsumerWidget { final String? initialSearchText; + final TabType tabType; - const SearchScreen({required this.initialSearchText}); + const SearchScreen({required this.initialSearchText, required this.tabType}); @override Widget build(BuildContext context, WidgetRef ref) { final formKey = useMemoized(() => GlobalKey()); + final selectedTabType = useState(tabType); + final isPrivate = selectedTabType.value == TabType.private; + final searchTextController = useTextEditingController( text: initialSearchText, ); @@ -52,11 +58,17 @@ class SearchScreen extends HookConsumerWidget { Future submitSearch(String query) async { if (activeBang != null && (formKey.currentState?.validate() == true)) { - final searchUri = await ref - .read(bangSearchProvider.notifier) - .triggerBangSearch(activeBang, query); + final searchUri = activeBang.getTemplateUrl(query); - await ref.read(tabRepositoryProvider.notifier).addTab(url: searchUri); + if (!isPrivate) { + await ref + .read(bangSearchProvider.notifier) + .triggerBangSearch(activeBang, query); + } + + await ref + .read(tabRepositoryProvider.notifier) + .addTab(url: searchUri, private: isPrivate); if (context.mounted) { ref.read(bottomSheetControllerProvider.notifier).dismiss(); @@ -75,43 +87,72 @@ class SearchScreen extends HookConsumerWidget { floating: true, pinned: true, automaticallyImplyLeading: false, - title: SearchField( - showBangIcon: showBangIcon.value, - textEditingController: searchTextController, - focusNode: searchFocusNode, - autofocus: true, - onSubmitted: (value) async { - if (value.isNotEmpty) { - var newUrl = uri_parser.tryParseUrl( - value, - eagerParsing: true, - ); + title: Align( + child: SegmentedButton( + showSelectedIcon: false, + segments: const [ + ButtonSegment( + value: TabType.regular, + label: Text('Regular'), + icon: Icon(MdiIcons.tab), + ), + ButtonSegment( + value: TabType.private, + label: Text('Private'), + icon: Icon(MdiIcons.tabUnselected), + ), + ], + selected: {selectedTabType.value}, + onSelectionChanged: (value) { + selectedTabType.value = value.first; + }, + ), + ), + bottom: PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: Padding( + padding: const EdgeInsets.only(left: 16.0), + child: SearchField( + showBangIcon: showBangIcon.value, + textEditingController: searchTextController, + focusNode: searchFocusNode, + autofocus: true, + onSubmitted: (value) async { + if (value.isNotEmpty) { + var newUrl = uri_parser.tryParseUrl( + value, + eagerParsing: true, + ); - if (newUrl == null) { - final defaultSearchBang = - ref.read(selectedBangDataProvider()) ?? - await ref.read(defaultSearchBangDataProvider.future); + if (newUrl == null) { + final defaultSearchBang = + ref.read(selectedBangDataProvider()) ?? + await ref.read( + defaultSearchBangDataProvider.future, + ); - newUrl = defaultSearchBang?.getTemplateUrl(value); - } + newUrl = defaultSearchBang?.getTemplateUrl(value); + } - if (newUrl != null) { - await ref - .read(tabRepositoryProvider.notifier) - .addTab(url: newUrl); + if (newUrl != null) { + await ref + .read(tabRepositoryProvider.notifier) + .addTab(url: newUrl, private: isPrivate); - if (context.mounted) { - ref - .read(bottomSheetControllerProvider.notifier) - .dismiss(); + if (context.mounted) { + ref + .read(bottomSheetControllerProvider.notifier) + .dismiss(); - context.pop(); + context.pop(); + } + } } - } - } - }, - activeBang: activeBang, - showSuggestions: true, + }, + activeBang: activeBang, + showSuggestions: true, + ), + ), ), ), const SliverToBoxAdapter(child: Divider()), @@ -120,10 +161,12 @@ class SearchScreen extends HookConsumerWidget { activeBang: activeBang, submitSearch: submitSearch, ), - const SliverToBoxAdapter(child: Divider()), TabSearch(searchTextListenable: sampledSearchText), FeedSearch(searchTextNotifier: sampledSearchText), - HistorySuggestions(searchTextListenable: sampledSearchText), + HistorySuggestions( + isPrivate: isPrivate, + searchTextListenable: sampledSearchText, + ), ], ), ), diff --git a/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart b/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart index ef4aa2fa..d8ae1000 100644 --- a/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart +++ b/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart @@ -15,9 +15,14 @@ import 'package:skeletonizer/skeletonizer.dart'; import 'package:sliver_tools/sliver_tools.dart'; class HistorySuggestions extends HookConsumerWidget { + final bool isPrivate; final ValueListenable searchTextListenable; - const HistorySuggestions({super.key, required this.searchTextListenable}); + const HistorySuggestions({ + super.key, + required this.isPrivate, + required this.searchTextListenable, + }); @override Widget build(BuildContext context, WidgetRef ref) { @@ -89,7 +94,7 @@ class HistorySuggestions extends HookConsumerWidget { case final Uri url) { await ref .read(tabRepositoryProvider.notifier) - .addTab(url: url); + .addTab(url: url, private: isPrivate); if (context.mounted) { ref