From d8191288819f67c5d647a4561688c2e0ac545eed Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sun, 5 May 2024 13:37:43 +0200 Subject: [PATCH] chore: Follow up search --- .../chat_search/chat_search_files_tab.dart | 9 +- .../chat_search/chat_search_images_tab.dart | 9 +- .../chat_search/chat_search_message_tab.dart | 29 +++--- lib/pages/chat_search/chat_search_page.dart | 93 ++++++++++++++++--- lib/pages/chat_search/chat_search_view.dart | 10 +- 5 files changed, 105 insertions(+), 45 deletions(-) diff --git a/lib/pages/chat_search/chat_search_files_tab.dart b/lib/pages/chat_search/chat_search_files_tab.dart index 37030ba0..db85b2af 100644 --- a/lib/pages/chat_search/chat_search_files_tab.dart +++ b/lib/pages/chat_search/chat_search_files_tab.dart @@ -28,11 +28,12 @@ class ChatSearchFilesTab extends StatelessWidget { return StreamBuilder( stream: searchStream, builder: (context, snapshot) { - if (searchStream == null) { + final events = snapshot.data?.$1; + if (searchStream == null || events == null) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.search_outlined, size: 64), + const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 8), Text( L10n.of(context)!.searchIn( @@ -44,10 +45,6 @@ class ChatSearchFilesTab extends StatelessWidget { ], ); } - final events = snapshot.data?.$1 - .where((event) => event.messageType == MessageTypes.File) - .toList() ?? - []; if (events.isEmpty) { return Column( diff --git a/lib/pages/chat_search/chat_search_images_tab.dart b/lib/pages/chat_search/chat_search_images_tab.dart index 809f0f2e..958055b2 100644 --- a/lib/pages/chat_search/chat_search_images_tab.dart +++ b/lib/pages/chat_search/chat_search_images_tab.dart @@ -27,11 +27,12 @@ class ChatSearchImagesTab extends StatelessWidget { return StreamBuilder( stream: searchStream, builder: (context, snapshot) { - if (searchStream == null) { + final events = snapshot.data?.$1; + if (searchStream == null || events == null) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.search_outlined, size: 64), + const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 8), Text( L10n.of(context)!.searchIn( @@ -43,10 +44,6 @@ class ChatSearchImagesTab extends StatelessWidget { ], ); } - final events = snapshot.data?.$1 - .where((event) => event.messageType == MessageTypes.Image) - .toList() ?? - []; if (events.isEmpty) { return Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/pages/chat_search/chat_search_message_tab.dart b/lib/pages/chat_search/chat_search_message_tab.dart index a904ed34..44f2adf0 100644 --- a/lib/pages/chat_search/chat_search_message_tab.dart +++ b/lib/pages/chat_search/chat_search_message_tab.dart @@ -49,15 +49,7 @@ class ChatSearchMessageTab extends StatelessWidget { ], ); } - final events = snapshot.data?.$1 - .where( - (event) => { - MessageTypes.Text, - MessageTypes.Notice, - }.contains(event.messageType), - ) - .toList() ?? - []; + final events = snapshot.data?.$1 ?? []; return SelectionArea( child: ListView.separated( @@ -166,14 +158,17 @@ class _MessageSearchResultListTile extends StatelessWidget { decorationColor: Theme.of(context).colorScheme.primary, ), onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), - text: event.calcLocalizedBodyFallback( - plaintextBody: true, - removeMarkdown: true, - MatrixLocals( - L10n.of(context)!, - ), - ), - maxLines: 4, + text: event + .calcLocalizedBodyFallback( + plaintextBody: true, + removeMarkdown: true, + MatrixLocals( + L10n.of(context)!, + ), + ) + .trim(), + maxLines: 7, + overflow: TextOverflow.ellipsis, ), trailing: IconButton( icon: const Icon( diff --git a/lib/pages/chat_search/chat_search_page.dart b/lib/pages/chat_search/chat_search_page.dart index a07bc4e9..306c6130 100644 --- a/lib/pages/chat_search/chat_search_page.dart +++ b/lib/pages/chat_search/chat_search_page.dart @@ -25,9 +25,11 @@ class ChatSearchController extends State Timeline? timeline; Stream<(List, String?)>? searchStream; + Stream<(List, String?)>? galleryStream; + Stream<(List, String?)>? fileStream; void restartSearch() { - if (tabController.index == 0 && searchController.text.isEmpty) { + if (searchController.text.isEmpty) { setState(() { searchStream = null; }); @@ -37,11 +39,11 @@ class ChatSearchController extends State searchStream = const Stream.empty(); }); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - startSearch(); + startMessageSearch(); }); } - void startSearch({ + void startMessageSearch({ String? prevBatch, List? previousSearchResult, }) async { @@ -54,12 +56,7 @@ class ChatSearchController extends State setState(() { searchStream = timeline .startSearch( - searchTerm: tabController.index == 0 ? searchController.text : null, - searchFunc: switch (tabController.index) { - 1 => (event) => event.messageType == MessageTypes.Image, - 2 => (event) => event.messageType == MessageTypes.File, - int() => null, - }, + searchTerm: searchController.text, prevBatch: prevBatch, requestHistoryCount: 1000, limit: 32, @@ -77,16 +74,90 @@ class ChatSearchController extends State }); } + void startGallerySearch({ + String? prevBatch, + List? previousSearchResult, + }) async { + final timeline = this.timeline ??= await room!.getTimeline(); + + setState(() { + galleryStream = timeline + .startSearch( + searchFunc: (event) => + event.messageType == MessageTypes.File || + (event.messageType == MessageTypes.Audio && + !event.content.containsKey('org.matrix.msc3245.voice')), + prevBatch: prevBatch, + requestHistoryCount: 1000, + limit: 32, + ) + .map( + (result) => ( + [ + if (previousSearchResult != null) ...previousSearchResult, + ...result.$1, + ], + result.$2, + ), + ) + .asBroadcastStream(); + }); + } + + void startFileSearch({ + String? prevBatch, + List? previousSearchResult, + }) async { + final timeline = this.timeline ??= await room!.getTimeline(); + + setState(() { + fileStream = timeline + .startSearch( + searchFunc: (event) => { + MessageTypes.Image, + MessageTypes.Video, + }.contains(event.messageType), + prevBatch: prevBatch, + requestHistoryCount: 1000, + limit: 32, + ) + .map( + (result) => ( + [ + if (previousSearchResult != null) ...previousSearchResult, + ...result.$1, + ], + result.$2, + ), + ) + .asBroadcastStream(); + }); + } + + void _onTabChanged() { + switch (tabController.index) { + case 1: + startGallerySearch(); + break; + case 2: + startFileSearch(); + break; + default: + restartSearch(); + break; + } + } + @override void initState() { super.initState(); tabController = TabController(initialIndex: 0, length: 3, vsync: this); - tabController.addListener(restartSearch); + tabController.addListener(_onTabChanged); } @override void dispose() { - tabController.removeListener(restartSearch); + tabController.removeListener(_onTabChanged); super.dispose(); } diff --git a/lib/pages/chat_search/chat_search_view.dart b/lib/pages/chat_search/chat_search_view.dart index 48c7cb60..c4c4824e 100644 --- a/lib/pages/chat_search/chat_search_view.dart +++ b/lib/pages/chat_search/chat_search_view.dart @@ -81,18 +81,18 @@ class ChatSearchView extends StatelessWidget { ChatSearchMessageTab( searchQuery: controller.searchController.text, room: room, - startSearch: controller.startSearch, + startSearch: controller.startMessageSearch, searchStream: controller.searchStream, ), ChatSearchImagesTab( room: room, - startSearch: controller.startSearch, - searchStream: controller.searchStream, + startSearch: controller.startGallerySearch, + searchStream: controller.galleryStream, ), ChatSearchFilesTab( room: room, - startSearch: controller.startSearch, - searchStream: controller.searchStream, + startSearch: controller.startFileSearch, + searchStream: controller.fileStream, ), ], ),