From 60d7df4496947b500fb27ffe93ddd3645ba8b214 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 7 Jul 2024 14:22:53 +0800 Subject: [PATCH] :sparkles: Search with tag & category --- ios/Podfile.lock | 18 +++---- lib/providers/content/post.dart | 5 +- lib/router.dart | 12 +++++ lib/screens/feed_search.dart | 88 ++++++++++++++++++++++++++++++++ lib/translations.dart | 6 +++ lib/widgets/posts/feed_tags.dart | 7 ++- 6 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 lib/screens/feed_search.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5e7ea13..12168bf 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -109,8 +109,6 @@ PODS: - GoogleUtilities/Privacy - image_picker_ios (0.0.1): - Flutter - - irondash_engine_context (0.0.1): - - Flutter - livekit_client (2.2.0): - Flutter - WebRTC-SDK (= 114.5735.10) @@ -127,6 +125,8 @@ PODS: - nanopb/encode (2.30910.0) - package_info_plus (0.4.5): - Flutter + - pasteboard (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -148,8 +148,6 @@ PODS: - sqflite (0.0.3): - Flutter - FlutterMacOS - - super_native_extensions (0.0.1): - - Flutter - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): - Flutter @@ -170,19 +168,18 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - - irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`) - livekit_client (from `.symlinks/plugins/livekit_client/ios`) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - pasteboard (from `.symlinks/plugins/pasteboard/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - sqflite (from `.symlinks/plugins/sqflite/darwin`) - - super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) @@ -226,8 +223,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_webrtc/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" - irondash_engine_context: - :path: ".symlinks/plugins/irondash_engine_context/ios" livekit_client: :path: ".symlinks/plugins/livekit_client/ios" media_kit_libs_ios_video: @@ -238,6 +233,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/media_kit_video/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + pasteboard: + :path: ".symlinks/plugins/pasteboard/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: @@ -250,8 +247,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/sentry_flutter/ios" sqflite: :path: ".symlinks/plugins/sqflite/darwin" - super_native_extensions: - :path: ".symlinks/plugins/super_native_extensions/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" volume_controller: @@ -279,13 +274,13 @@ SPEC CHECKSUMS: GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9 livekit_client: 2b3f5185f95d46d62d3570bf981f3d98ad3051e2 media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e nanopb: 438bc412db1928dac798aa6fd75726007be04262 package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 @@ -295,7 +290,6 @@ SPEC CHECKSUMS: Sentry: 016de45ee5ce5fca2a829996f1bfafeb5e62e8b4 sentry_flutter: 5fb57c5b7e6427a9dc1fedde4269eb65823982d4 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 diff --git a/lib/providers/content/post.dart b/lib/providers/content/post.dart index beb1f17..da601e1 100644 --- a/lib/providers/content/post.dart +++ b/lib/providers/content/post.dart @@ -7,10 +7,13 @@ class PostProvider extends GetConnect { httpClient.baseUrl = ServiceFinder.services['interactive']; } - Future listFeed(int page, {int? realm}) async { + Future listFeed(int page, + {int? realm, String? tag, category}) async { final queries = [ 'take=${10}', 'offset=$page', + if (tag != null) 'tag=$tag', + if (category != null) 'category=$category', if (realm != null) 'realmId=$realm', ]; final resp = await get('/api/feed?${queries.join('&')}'); diff --git a/lib/router.dart b/lib/router.dart index aa990f0..82ea7e7 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -8,6 +8,7 @@ import 'package:solian/screens/channel/channel_chat.dart'; import 'package:solian/screens/channel/channel_detail.dart'; import 'package:solian/screens/channel/channel_organize.dart'; import 'package:solian/screens/chat.dart'; +import 'package:solian/screens/feed_search.dart'; import 'package:solian/screens/posts/post_detail.dart'; import 'package:solian/screens/realms.dart'; import 'package:solian/screens/realms/realm_detail.dart'; @@ -47,6 +48,17 @@ abstract class AppRouter { name: 'feed', builder: (context, state) => const FeedScreen(), ), + GoRoute( + path: '/feed/search', + name: 'feedSearch', + builder: (context, state) => TitleShell( + state: state, + child: FeedSearchScreen( + tag: state.uri.queryParameters['tag'], + category: state.uri.queryParameters['category'], + ), + ), + ), GoRoute( path: '/posts/view/:alias', name: 'postDetail', diff --git a/lib/screens/feed_search.dart b/lib/screens/feed_search.dart new file mode 100644 index 0000000..8e5abbb --- /dev/null +++ b/lib/screens/feed_search.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:solian/models/feed.dart'; +import 'package:solian/models/pagination.dart'; +import 'package:solian/providers/content/post.dart'; +import 'package:solian/widgets/posts/feed_list.dart'; + +class FeedSearchScreen extends StatefulWidget { + final String? tag; + final String? category; + + const FeedSearchScreen({super.key, this.tag, this.category}); + + @override + State createState() => _FeedSearchScreenState(); +} + +class _FeedSearchScreenState extends State { + final PagingController _pagingController = + PagingController(firstPageKey: 0); + + getPosts(int pageKey) async { + final PostProvider provider = Get.find(); + + Response resp; + try { + resp = await provider.listFeed( + pageKey, + tag: widget.tag, + category: widget.category, + ); + } catch (e) { + _pagingController.error = e; + return; + } + + final PaginationResult result = PaginationResult.fromJson(resp.body); + final parsed = result.data?.map((e) => FeedRecord.fromJson(e)).toList(); + if (parsed != null && parsed.length >= 10) { + _pagingController.appendPage(parsed, pageKey + parsed.length); + } else if (parsed != null) { + _pagingController.appendLastPage(parsed); + } + } + + @override + void initState() { + super.initState(); + + _pagingController.addPageRequestListener(getPosts); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Material( + color: Theme.of(context).colorScheme.surface, + child: Column( + children: [ + if (widget.tag != null) + ListTile( + leading: const Icon(Icons.label), + tileColor: Theme.of(context).colorScheme.surfaceContainer, + title: Text('feedSearchWithTag'.trParams({'key': widget.tag!})), + ), + if (widget.category != null) + ListTile( + leading: const Icon(Icons.category), + tileColor: Theme.of(context).colorScheme.surfaceContainer, + title: Text('feedSearchWithCategory'.trParams({'key': widget.category!})), + ), + Expanded( + child: RefreshIndicator( + onRefresh: () => Future.sync(() => _pagingController.refresh()), + child: CustomScrollView( + slivers: [ + FeedListWidget(controller: _pagingController), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/translations.dart b/lib/translations.dart index 6851a6a..a3ccbe9 100644 --- a/lib/translations.dart +++ b/lib/translations.dart @@ -11,6 +11,9 @@ class SolianMessages extends Translations { 'reset': 'Reset', 'page': 'Page', 'feed': 'Feed', + 'feedSearch': 'Search Feed', + 'feedSearchWithTag': 'Searching with tag #@key', + 'feedSearchWithCategory': 'Searching in category @category', 'chat': 'Chat', 'apply': 'Apply', 'cancel': 'Cancel', @@ -265,6 +268,9 @@ class SolianMessages extends Translations { 'delete': '删除', 'page': '页面', 'feed': '资讯', + 'feedSearch': '搜索资讯', + 'feedSearchWithTag': '检索带有 #@key 标签的资讯', + 'feedSearchWithCategory': '检索位于分类 @category 的资讯', 'chat': '聊天', 'apply': '应用', 'search': '搜索', diff --git a/lib/widgets/posts/feed_tags.dart b/lib/widgets/posts/feed_tags.dart index 6aa3cd3..225216c 100644 --- a/lib/widgets/posts/feed_tags.dart +++ b/lib/widgets/posts/feed_tags.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:solian/models/feed.dart'; +import 'package:solian/router.dart'; class FeedTagsList extends StatelessWidget { final List tags; @@ -36,7 +37,11 @@ class FeedTagsList extends StatelessWidget { ), ), ), - onTap: () {}, + onTap: () { + AppRouter.instance.pushNamed('feedSearch', queryParameters: { + 'tag': x.alias, + }); + }, ), ) .toList(),