From fbfe01d0b3161a7c0c67d030ef1a5cb383b9fb96 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Mon, 17 Jun 2024 19:34:40 +0200 Subject: [PATCH] fix show site search when no bangs avalilable --- .../presentation/widgets/site_search.dart | 135 ++++++++---------- .../presentation/widgets/web_page_dialog.dart | 63 ++++++-- 2 files changed, 113 insertions(+), 85 deletions(-) diff --git a/app/lib/features/bangs/presentation/widgets/site_search.dart b/app/lib/features/bangs/presentation/widgets/site_search.dart index 5b277234..2db0bf8a 100644 --- a/app/lib/features/bangs/presentation/widgets/site_search.dart +++ b/app/lib/features/bangs/presentation/widgets/site_search.dart @@ -1,4 +1,4 @@ -import 'package:bang_navigator/features/bangs/domain/providers.dart'; +import 'package:bang_navigator/features/bangs/data/models/bang_data.dart'; import 'package:bang_navigator/features/bangs/domain/repositories/data.dart'; import 'package:bang_navigator/features/bangs/presentation/widgets/bang_chips.dart'; import 'package:bang_navigator/features/bangs/presentation/widgets/search_field.dart'; @@ -11,32 +11,24 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; class SiteSearch extends HookConsumerWidget { final String domain; + final List availableBangs; - const SiteSearch({required this.domain, super.key}); + const SiteSearch({ + required this.domain, + required this.availableBangs, + super.key, + }); @override Widget build(BuildContext context, WidgetRef ref) { final formKey = useMemoized(() => GlobalKey()); - final availableBangsAsync = ref.watch( - bangDataListProvider( - filter: ( - domain: domain, - groups: null, - categoryFilter: null, - orderMostFrequentFirst: true, - ), - ), - ); - final availableBangCount = availableBangsAsync.valueOrNull?.length ?? 0; - final selectedBang = ref.watch( selectedBangDataProvider(domain: domain) .select((value) => value.valueOrNull), ); - final activeBang = - selectedBang ?? availableBangsAsync.valueOrNull?.firstOrNull; + final activeBang = selectedBang ?? availableBangs.firstOrNull; final textController = useTextEditingController(); @@ -54,67 +46,58 @@ class SiteSearch extends HookConsumerWidget { } } - return availableBangsAsync.when( - data: (availableBangs) { - return Form( - key: formKey, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (availableBangCount > 1) - SizedBox( - height: 48, - width: double.maxFinite, - child: BangChips( - availableBangs: availableBangs, - selectedBang: selectedBang, - onSelected: (trigger) { - ref - .read( - selectedBangTriggerProvider(domain: domain) - .notifier, - ) - .setTrigger(trigger); - }, - onDeleted: (trigger) { - if (ref.read( - selectedBangTriggerProvider(domain: domain), - ) == - trigger) { - ref - .read( - selectedBangTriggerProvider(domain: domain) - .notifier, - ) - .clearTrigger(); - } - }, - ), - ), - SearchField( - textController: textController, - activeBang: activeBang, - onFieldSubmitted: (_) async { - await submitSearch(); - }, - ), - const SizedBox( - height: 12, - ), - SizedBox( - width: double.infinity, - child: FilledButton.icon( - onPressed: submitSearch, - label: const Text('Search on Site'), - icon: const Icon(MdiIcons.cloudSearch), - ), - ), - ], + return Form( + key: formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 48, + width: double.maxFinite, + child: BangChips( + availableBangs: availableBangs, + selectedBang: selectedBang, + onSelected: (trigger) { + ref + .read( + selectedBangTriggerProvider(domain: domain).notifier, + ) + .setTrigger(trigger); + }, + onDeleted: (trigger) { + if (ref.read( + selectedBangTriggerProvider(domain: domain), + ) == + trigger) { + ref + .read( + selectedBangTriggerProvider(domain: domain).notifier, + ) + .clearTrigger(); + } + }, + ), ), - ); - }, - error: (error, stackTrace) => const SizedBox.shrink(), - loading: () => const SizedBox(height: 48), + SearchField( + textController: textController, + activeBang: activeBang, + onFieldSubmitted: (_) async { + await submitSearch(); + }, + ), + const SizedBox( + height: 12, + ), + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: submitSearch, + label: const Text('Search on Site'), + icon: const Icon(MdiIcons.cloudSearch), + ), + ), + ], + ), ); } } diff --git a/app/lib/features/web_view/presentation/widgets/web_page_dialog.dart b/app/lib/features/web_view/presentation/widgets/web_page_dialog.dart index 59753817..e08df7c5 100644 --- a/app/lib/features/web_view/presentation/widgets/web_page_dialog.dart +++ b/app/lib/features/web_view/presentation/widgets/web_page_dialog.dart @@ -1,4 +1,6 @@ import 'package:bang_navigator/domain/entities/web_page_info.dart'; +import 'package:bang_navigator/features/bangs/data/models/bang_data.dart'; +import 'package:bang_navigator/features/bangs/domain/providers.dart'; import 'package:bang_navigator/features/bangs/presentation/widgets/site_search.dart'; import 'package:bang_navigator/features/search_browser/domain/entities/modes.dart'; import 'package:bang_navigator/features/search_browser/utils/url_builder.dart' @@ -8,6 +10,7 @@ import 'package:bang_navigator/features/share_intent/domain/entities/shared_cont import 'package:bang_navigator/features/web_view/presentation/controllers/switch_new_tab.dart'; import 'package:bang_navigator/features/web_view/presentation/widgets/favicon.dart'; import 'package:bang_navigator/presentation/controllers/website_title.dart'; +import 'package:bang_navigator/presentation/widgets/failure_widget.dart'; import 'package:bang_navigator/utils/ui_helper.dart' as ui_helper; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -16,7 +19,6 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:share_plus/share_plus.dart'; -import 'package:skeletonizer/skeletonizer.dart'; class LoadingWebPageDialog extends HookConsumerWidget { final Uri url; @@ -29,11 +31,14 @@ class LoadingWebPageDialog extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final pageInfoAsync = ref.watch(pageInfoProvider(url)); - return Skeletonizer( - enabled: pageInfoAsync.isLoading, - child: WebPageDialog( - page: pageInfoAsync.valueOrNull ?? - WebPageInfo(url: url, favicon: null, title: ''), + return pageInfoAsync.when( + data: (pageInfo) => WebPageDialog( + page: pageInfo, + onDismiss: onDismiss, + ), + error: (error, stackTrace) => SizedBox.shrink(), + loading: () => ModalBarrier( + color: Theme.of(context).dialogTheme.barrierColor ?? Colors.black54, onDismiss: onDismiss, ), ); @@ -60,6 +65,18 @@ class WebPageDialog extends HookConsumerWidget { .select((value) => value.valueOrNull?.incognitoMode ?? false), ); + final availableBangsAsync = ref.watch( + bangDataListProvider( + filter: ( + domain: page.url.host, + groups: null, + categoryFilter: null, + orderMostFrequentFirst: true, + ), + ), + ); + final availableBangCount = availableBangsAsync.valueOrNull?.length; + final formKey = useMemoized(() => GlobalKey()); final urlTextController = useTextEditingController(text: page.url.toString()); @@ -98,6 +115,7 @@ class WebPageDialog extends HookConsumerWidget { controller: urlTextController, enableIMEPersonalizedLearning: !incognitoEnabled, decoration: InputDecoration( + labelText: 'URL', suffixIcon: (webViewController != null) ? IconButton( onPressed: () async { @@ -137,11 +155,38 @@ class WebPageDialog extends HookConsumerWidget { const Divider(), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: SiteSearch( - domain: page.url.host, + child: availableBangsAsync.when( + data: (availableBangs) { + if (availableBangs.isEmpty) { + return const SizedBox.shrink(); + } + + return SiteSearch( + domain: page.url.host, + availableBangs: availableBangs, + ); + }, + error: (error, stackTrace) => FailureWidget( + title: 'Could not load bangs', + exception: error, + ), + loading: () => SiteSearch( + domain: page.url.host, + availableBangs: [ + BangData( + websiteName: 'websiteName', + domain: 'domain', + trigger: 'trigger', + urlTemplate: 'urlTemplate', + ), + ], + ), ), ), - const Divider(), + if (availableBangsAsync.isLoading || + availableBangCount == null || + availableBangCount > 0) + const Divider(), ListTile( leading: const Icon(MdiIcons.contentCopy), title: const Text('Copy address'),