scroll sheet for suggestions

This commit is contained in:
Fabian Freund
2025-10-02 14:37:51 +02:00
parent e435487284
commit 4698338e93
2 changed files with 48 additions and 29 deletions
@@ -43,7 +43,7 @@ import 'package:weblibre/utils/uri_parser.dart' as uri_parser;
class SiteSearch extends HookConsumerWidget { class SiteSearch extends HookConsumerWidget {
final String domain; final String domain;
final List<BangData> availableBangs; final List<BangData> availableBangs;
final String? initialText; final TextEditingController? controller;
final bool searchInNewTab; final bool searchInNewTab;
final Widget? label; final Widget? label;
@@ -51,14 +51,14 @@ class SiteSearch extends HookConsumerWidget {
required this.domain, required this.domain,
required this.availableBangs, required this.availableBangs,
super.key, super.key,
this.initialText, this.controller,
this.searchInNewTab = false, this.searchInNewTab = false,
this.label, this.label,
}); });
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final searchTextController = useTextEditingController(text: initialText); final searchTextController = controller ?? useTextEditingController();
final searchFocusNode = useFocusNode(); final searchFocusNode = useFocusNode();
useListenableCallback(searchTextController, () { useListenableCallback(searchTextController, () {
@@ -39,6 +39,7 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
import 'package:weblibre/presentation/hooks/listenable_callback.dart';
import 'package:weblibre/presentation/widgets/share_tile.dart'; import 'package:weblibre/presentation/widgets/share_tile.dart';
import 'package:weblibre/presentation/widgets/website_feed_tile.dart'; import 'package:weblibre/presentation/widgets/website_feed_tile.dart';
import 'package:weblibre/presentation/widgets/website_title_tile.dart'; import 'package:weblibre/presentation/widgets/website_title_tile.dart';
@@ -76,6 +77,48 @@ class ViewTabSheetWidget extends HookConsumerWidget {
final headerKey = useMemoized(() => GlobalKey()); final headerKey = useMemoized(() => GlobalKey());
final textFieldKey = useMemoized(() => GlobalKey()); final textFieldKey = useMemoized(() => GlobalKey());
final scrolledTo = useRef(0.0);
final searchTextController = useTextEditingController(
text: initialTabState.url.toString(),
);
Future<void> scroll() async {
if (!context.mounted) return;
final header = headerKey.currentContext?.findRenderObject();
final text = textFieldKey.currentContext?.findRenderObject();
if (header case final RenderBox headerBox) {
if (text case final RenderBox textBox) {
final totalHeight =
headerBox.size.height +
textBox.size.height +
kToolbarHeight +
MediaQuery.of(context).viewInsets.bottom;
final relative = (totalHeight / MediaQuery.of(context).size.height)
.clamp(0.0, 1.0);
if (draggableScrollableController.size < relative &&
relative > scrolledTo.value) {
await draggableScrollableController.animateTo(
relative,
duration: const Duration(milliseconds: 150),
curve: Curves.easeInOut,
);
scrolledTo.value = relative;
}
}
}
}
useListenableCallback(searchTextController, () {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await scroll();
});
});
final availableBangs = ref.watch( final availableBangs = ref.watch(
bangListProvider( bangListProvider(
domain: initialTabState.url.host, domain: initialTabState.url.host,
@@ -83,33 +126,9 @@ class ViewTabSheetWidget extends HookConsumerWidget {
).select((value) => value.value ?? const []), ).select((value) => value.value ?? const []),
); );
final scrolledTo = useRef(0.0);
useEffect(() { useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (!context.mounted) return; await scroll();
final header = headerKey.currentContext?.findRenderObject();
final text = textFieldKey.currentContext?.findRenderObject();
if (header case final RenderBox headerBox) {
if (text case final RenderBox textBox) {
final totalHeight =
headerBox.size.height + textBox.size.height + kToolbarHeight;
final relative = (totalHeight / MediaQuery.of(context).size.height)
.clamp(0.0, 1.0);
if (draggableScrollableController.size < relative &&
relative > scrolledTo.value) {
await draggableScrollableController.animateTo(
relative,
duration: const Duration(milliseconds: 150),
curve: Curves.easeInOut,
);
scrolledTo.value = relative;
}
}
}
}); });
return null; return null;
@@ -196,7 +215,7 @@ class ViewTabSheetWidget extends HookConsumerWidget {
key: textFieldKey, key: textFieldKey,
domain: initialTabState.url.host, domain: initialTabState.url.host,
availableBangs: availableBangs, availableBangs: availableBangs,
initialText: initialTabState.url.toString(), controller: searchTextController,
label: const Text('Address'), label: const Text('Address'),
), ),
), ),