diff --git a/apps/weblibre/lib/core/routing/routes.browser.dart b/apps/weblibre/lib/core/routing/routes.browser.dart index e7040a00..02a86869 100644 --- a/apps/weblibre/lib/core/routing/routes.browser.dart +++ b/apps/weblibre/lib/core/routing/routes.browser.dart @@ -91,6 +91,8 @@ class SearchRoute extends GoRouteData with $SearchRoute { final bool launchedFromIntent; + final bool autoSubmitSearch; + /// When provided, the search screen will load URLs into this existing tab /// instead of creating a new tab. This also changes the UI to show /// site-specific bangs instead of the tab type selector. @@ -100,6 +102,7 @@ class SearchRoute extends GoRouteData with $SearchRoute { required this.tabType, this.searchText = SearchRoute.emptySearchText, this.launchedFromIntent = false, + this.autoSubmitSearch = false, this.tabId, }); @@ -111,6 +114,7 @@ class SearchRoute extends GoRouteData with $SearchRoute { ? null : searchText, launchedFromIntent: launchedFromIntent, + autoSubmitSearch: autoSubmitSearch, tabId: tabId, ); } diff --git a/apps/weblibre/lib/core/routing/routes.g.dart b/apps/weblibre/lib/core/routing/routes.g.dart index 64315fa8..dda85d12 100644 --- a/apps/weblibre/lib/core/routing/routes.g.dart +++ b/apps/weblibre/lib/core/routing/routes.g.dart @@ -632,6 +632,13 @@ mixin $SearchRoute on GoRouteData { _$boolConverter, ) ?? false, + autoSubmitSearch: + _$convertMapValue( + 'auto-submit-search', + state.uri.queryParameters, + _$boolConverter, + ) ?? + false, tabId: state.uri.queryParameters['tab-id'], ); @@ -643,6 +650,8 @@ mixin $SearchRoute on GoRouteData { queryParams: { if (_self.launchedFromIntent != false) 'launched-from-intent': _self.launchedFromIntent.toString(), + if (_self.autoSubmitSearch != false) + 'auto-submit-search': _self.autoSubmitSearch.toString(), if (_self.tabId != null) 'tab-id': _self.tabId, }, ); diff --git a/apps/weblibre/lib/features/bangs/data/models/web_search_bang.dart b/apps/weblibre/lib/features/bangs/data/models/web_search_bang.dart index d8d71aea..dca4544f 100644 --- a/apps/weblibre/lib/features/bangs/data/models/web_search_bang.dart +++ b/apps/weblibre/lib/features/bangs/data/models/web_search_bang.dart @@ -21,4 +21,4 @@ const webSearchBangKey = BangKey( ); bool isWebSearchBang(BangData? bang) => - bang != null && bang.group == BangGroup.weblibre; + bang != null && bang.toKey() == webSearchBangKey; diff --git a/apps/weblibre/lib/features/geckoview/domain/providers.dart b/apps/weblibre/lib/features/geckoview/domain/providers.dart index 99d9737c..e62c3a0b 100644 --- a/apps/weblibre/lib/features/geckoview/domain/providers.dart +++ b/apps/weblibre/lib/features/geckoview/domain/providers.dart @@ -26,6 +26,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/providers/router.dart'; import 'package:weblibre/core/routing/routes.dart'; +import 'package:weblibre/features/bangs/data/models/web_search_bang.dart'; import 'package:weblibre/features/bangs/domain/providers/bangs.dart'; import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; @@ -83,6 +84,20 @@ GeckoSelectionActionService selectionActionService(Ref ref) { .effectiveDefaultCreateTabType, ); + if (isWebSearchBang(searchBang)) { + final router = await ref.read(routerProvider.future); + if (!ref.mounted) return; + + await router.push( + SearchRoute( + tabType: tabMode.toTabType(), + searchText: text, + autoSubmitSearch: true, + ).location, + ); + return; + } + await ref .read(tabRepositoryProvider.notifier) .addTab( diff --git a/apps/weblibre/lib/features/geckoview/domain/providers.g.dart b/apps/weblibre/lib/features/geckoview/domain/providers.g.dart index f38a8351..2be6e07c 100644 --- a/apps/weblibre/lib/features/geckoview/domain/providers.g.dart +++ b/apps/weblibre/lib/features/geckoview/domain/providers.g.dart @@ -55,7 +55,7 @@ final class SelectionActionServiceProvider } String _$selectionActionServiceHash() => - r'78593799e8d903de415cf49ebb3acfb73e45d878'; + r'c2cdd69d3dc4c2fe4bb54658d76ca26efb5bfc74'; @ProviderFor(eventService) final eventServiceProvider = EventServiceProvider._(); diff --git a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart index c7262813..7b0f0593 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart @@ -30,6 +30,7 @@ import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/providers/device_info.dart'; import 'package:weblibre/core/providers/router.dart'; import 'package:weblibre/core/routing/routes.dart'; +import 'package:weblibre/features/bangs/data/models/web_search_bang.dart'; import 'package:weblibre/features/bangs/domain/providers/bangs.dart'; import 'package:weblibre/features/bangs/domain/services/search_history_cleanup.dart'; import 'package:weblibre/features/geckoview/domain/entities/tab_container_selection.dart'; @@ -436,6 +437,19 @@ class _BrowserViewState extends ConsumerState ref.read(selectedBangDataProvider()) ?? await ref.read(defaultSearchBangProvider.future); + if (bang != null && isWebSearchBang(bang)) { + final router = await ref.read(routerProvider.future); + await router.push( + SearchRoute( + tabType: tabMode.toTabType(), + searchText: sharedContent.text, + launchedFromIntent: true, + autoSubmitSearch: true, + ).location, + ); + break; + } + await ref .read(tabRepositoryProvider.notifier) .addTab( diff --git a/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart b/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart index cd14f126..974cac62 100644 --- a/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart +++ b/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart @@ -83,6 +83,7 @@ class SearchScreen extends HookConsumerWidget { final String? initialSearchText; final TabType tabType; final bool launchedFromIntent; + final bool autoSubmitSearch; /// When provided, URLs will be loaded into this existing tab. /// When null, a new tab will be created. @@ -93,6 +94,7 @@ class SearchScreen extends HookConsumerWidget { required this.initialSearchText, required this.tabType, this.launchedFromIntent = false, + this.autoSubmitSearch = false, this.tabId, }); @@ -430,6 +432,25 @@ class SearchScreen extends HookConsumerWidget { } } + final autoSubmittedInitialSearch = useRef(false); + useEffect(() { + if (!autoSubmitSearch || + autoSubmittedInitialSearch.value || + initialSearchText == null || + initialSearchText!.trim().isEmpty || + activeBang == null || + !isWebSearchBang(activeBang)) { + return null; + } + + autoSubmittedInitialSearch.value = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + unawaited(resolveSearchUri(activeBang, initialSearchText!)); + }); + + return null; + }, [autoSubmitSearch, initialSearchText, activeBang]); + // Persist the results scroll offset across navigation so returning to // the search screen after opening a result restores the user's place // instead of jumping back to the top. The offset provider is reset on