implemented find in page

This commit is contained in:
Fabian Freund
2024-08-14 11:43:41 +02:00
parent 1dd37f44b6
commit 60ad009bb0
6 changed files with 153 additions and 2 deletions
@@ -7,7 +7,7 @@ part of 'sync.dart';
// **************************************************************************
String _$bangSyncRepositoryHash() =>
r'1e6341c8daf25aaee61d158f94445564d4450a9e';
r'86933b05d01629c67ed0443df91e991c40136423';
/// See also [BangSyncRepository].
@ProviderFor(BangSyncRepository)
@@ -7,7 +7,7 @@ part of 'sync.dart';
// **************************************************************************
String _$hostSyncRepositoryHash() =>
r'22b89d3687c415441f99caa4d77dabaeb4969534';
r'5eed0c51e1b1e4dd1241634e297aff283eef01c5';
/// See also [HostSyncRepository].
@ProviderFor(HostSyncRepository)
@@ -125,3 +125,15 @@ class ActiveChatModel extends _$ActiveChatModel {
return ChatModel.gpt4o;
}
}
@Riverpod(keepAlive: true)
class ShowFindInPage extends _$ShowFindInPage {
void update(bool show) {
state = show;
}
@override
bool build() {
return false;
}
}
@@ -396,5 +396,20 @@ final activeChatModelProvider =
);
typedef _$ActiveChatModel = Notifier<ChatModel>;
String _$showFindInPageHash() => r'7ee5703f7d0c7e8a8dd6b0849d7b1e0a41fe24d9';
/// See also [ShowFindInPage].
@ProviderFor(ShowFindInPage)
final showFindInPageProvider = NotifierProvider<ShowFindInPage, bool>.internal(
ShowFindInPage.new,
name: r'showFindInPageProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$showFindInPageHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$ShowFindInPage = Notifier<bool>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
@@ -434,6 +434,14 @@ class KagiScreen extends HookConsumerWidget {
child: const Text('Share'),
),
const Divider(),
MenuItemButton(
onPressed: () async {
ref.read(showFindInPageProvider.notifier).update(true);
},
leadingIcon: const Icon(Icons.search),
child: const Text('Find in page'),
),
const Divider(),
MenuItemButton(
onPressed: () async {
await activeWebView?.currentController?.reload();
@@ -216,6 +216,28 @@ class _WebViewState extends ConsumerState<WebView> {
);
final webViewProgress = useValueNotifier(100);
final inPageSearchResult =
useValueNotifier<({int activeMatchOrdinal, int numberOfMatches})?>(
null,
);
final findInteractionController = useMemoized(
() => FindInteractionController(
onFindResultReceived: (
controller,
activeMatchOrdinal,
numberOfMatches,
isDoneCounting,
) {
if (isDoneCounting) {
inPageSearchResult.value = (
activeMatchOrdinal: activeMatchOrdinal,
numberOfMatches: numberOfMatches,
);
}
},
),
);
useOnAppLifecycleStateChange((previous, current) async {
switch (current) {
@@ -242,6 +264,7 @@ class _WebViewState extends ConsumerState<WebView> {
InAppWebView(
initialUrlRequest: URLRequest(url: WebUri.uri(widget.page.value.url)),
initialSettings: initialSettings,
findInteractionController: findInteractionController,
contextMenu: ContextMenu(
menuItems: [
ContextMenuItem(
@@ -524,6 +547,99 @@ class _WebViewState extends ConsumerState<WebView> {
},
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: HookConsumer(
builder: (context, ref, child) {
final showFindInPage = ref.watch(showFindInPageProvider);
final textController = useTextEditingController();
final progress = useValueListenable(webViewProgress);
return Visibility(
visible: showFindInPage,
child: Padding(
padding:
EdgeInsets.only(bottom: (progress < 100) ? 4.0 : 0.0),
child: Material(
child: Row(
children: [
const SizedBox(width: 8),
Expanded(
child: TextField(
controller: textController,
autofocus: true,
autocorrect: false,
decoration: const InputDecoration.collapsed(
hintText: 'Find in page',
),
keyboardType: TextInputType.text,
onSubmitted: (value) async {
if (value == '') {
inPageSearchResult.value = null;
await findInteractionController.clearMatches();
} else {
await findInteractionController.findAll(
find: value,
);
}
},
),
),
HookConsumer(
builder: (context, ref, child) {
final searchResult =
useValueListenable(inPageSearchResult);
if (searchResult != null) {
if (searchResult.numberOfMatches == 0) {
return const Text('Not found');
}
return Text(
'${searchResult.activeMatchOrdinal + 1} of ${searchResult.numberOfMatches}',
);
}
return const SizedBox.shrink();
},
),
IconButton(
icon: const Icon(Icons.arrow_upward),
onPressed: () async {
await findInteractionController.findNext(
forward: false,
);
},
),
IconButton(
icon: const Icon(Icons.arrow_downward),
onPressed: () async {
await findInteractionController.findNext();
},
),
IconButton(
icon: const Icon(Icons.clear),
onPressed: () async {
ref
.read(showFindInPageProvider.notifier)
.update(false);
inPageSearchResult.value = null;
await findInteractionController.clearMatches();
textController.clear();
},
),
],
),
),
),
);
},
),
),
],
);
}