diff --git a/api/lib/src/helpers/search_helper.dart b/api/lib/src/helpers/search_helper.dart index 1e4c144c3bc9..0a8ac0d70a13 100644 --- a/api/lib/src/helpers/search_helper.dart +++ b/api/lib/src/helpers/search_helper.dart @@ -5,9 +5,17 @@ import '../../butterfly_api.dart'; class SearchResult { final String name; final Point location; + final String? page; final T item; - SearchResult(this.name, this.location, this.item); + SearchResult(this.name, this.location, this.item, [this.page]); + + SearchResult withPage(String page) => SearchResult( + name, + location, + item, + page, + ); } extension ElementSearchHelper on PadElement { @@ -47,21 +55,30 @@ extension WaypointSearchHelper on Waypoint { } } +extension GlobalSearchHelper on NoteData { + Iterable search(Pattern query) sync* { + for (final pageName in getPages()) { + final page = getPage(pageName); + if (page == null) continue; + yield SearchResult(pageName, Point(0, 0), page, pageName); + yield* page.search(query).map((e) => e.withPage(pageName)); + } + } +} + extension SearchHelper on DocumentPage { - List search(Pattern query) { - final results = []; + Iterable search(Pattern query) sync* { for (final area in areas) { final result = area.matches(query); - if (result != null) results.add(result); + if (result != null) yield result; } for (final waypoint in waypoints) { final result = waypoint.matches(query); - if (result != null) results.add(result); + if (result != null) yield result; } for (final element in content) { final result = element.matches(query); - if (result != null) results.add(result); + if (result != null) yield result; } - return results; } } diff --git a/app/lib/dialogs/search.dart b/app/lib/dialogs/search.dart index 64c044e10fa3..7832b09edc5c 100644 --- a/app/lib/dialogs/search.dart +++ b/app/lib/dialogs/search.dart @@ -18,12 +18,13 @@ class SearchDialog extends StatefulWidget { State createState() => _SearchDialogState(); } -Future> _searchIsolate(DocumentPage page, String query) => +Future> _searchIsolate( + DocumentPage page, String query) => Isolate.run(() => page.search(RegExp(query, caseSensitive: false))); class _SearchDialogState extends State { final TextEditingController _searchController = TextEditingController(); - Future> _searchResults = Future.value([]); + Future> _searchResults = Future.value([]); final FocusNode _focusNode = FocusNode(); @override @@ -114,7 +115,7 @@ class _SearchDialogState extends State { ), const SizedBox(height: 16), Flexible( - child: FutureBuilder>( + child: FutureBuilder>( future: _searchResults, builder: (context, snapshot) { if (snapshot.hasError) { @@ -129,7 +130,7 @@ class _SearchDialogState extends State { ], ); } - final results = snapshot.data ?? []; + final results = snapshot.data?.toList() ?? []; return ListView.builder( itemCount: results.length, shrinkWrap: true,