From e26b21d03f5f09b8bb1b2e5067f51c79a923a71c Mon Sep 17 00:00:00 2001 From: Simon Ding Date: Thu, 18 Jul 2024 13:04:03 +0800 Subject: [PATCH] feat: change search behavior --- ui/lib/main.dart | 32 ++++++++++++++------- ui/lib/movie_watchlist.dart | 13 ++++----- ui/lib/providers/welcome_data.dart | 46 +++++++++++++++--------------- ui/lib/search.dart | 29 ++++++++++++------- ui/lib/tv_details.dart | 13 ++++----- 5 files changed, 73 insertions(+), 60 deletions(-) diff --git a/ui/lib/main.dart b/ui/lib/main.dart index b246043..eff858f 100644 --- a/ui/lib/main.dart +++ b/ui/lib/main.dart @@ -34,19 +34,30 @@ class MyApp extends StatelessWidget { backgroundColor: Theme.of(context).colorScheme.inversePrimary, // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. - title: Row( + title: const Row( children: [ - const Text("Polaris"), - const SizedBox( - width: 100, - ), - IconButton( - tooltip: "搜索剧集", - onPressed: () => context.go(SearchPage.route), - icon: const Icon(Icons.search)), + Text("Polaris"), ], ), actions: [ + SearchAnchor(builder: + (BuildContext context, SearchController controller) { + return Container( + constraints: + const BoxConstraints(maxWidth: 300, maxHeight: 40), + child: SearchBar( + hintText: "搜索电影和电视剧...", + leading: const Icon(Icons.search), + controller: controller, + onSubmitted: (value) => context.go(Uri( + path: SearchPage.route, + queryParameters: {'query': value}).toString()), + ), + ); + }, suggestionsBuilder: + (BuildContext context, SearchController controller) { + return [Text("dadada")]; + }), FutureBuilder( future: APIs.isLoggedIn(), builder: (context, snapshot) { @@ -126,7 +137,8 @@ class MyApp extends StatelessWidget { ), GoRoute( path: SearchPage.route, - builder: (context, state) => const SearchPage(), + builder: (context, state) => + SearchPage(query: state.uri.queryParameters["query"]), ), GoRoute( path: SystemSettingsPage.route, diff --git a/ui/lib/movie_watchlist.dart b/ui/lib/movie_watchlist.dart index 5acc92b..b709c36 100644 --- a/ui/lib/movie_watchlist.dart +++ b/ui/lib/movie_watchlist.dart @@ -21,19 +21,16 @@ class MovieDetailsPage extends ConsumerStatefulWidget { @override ConsumerState createState() { - return _MovieDetailsPageState(id: id); + return _MovieDetailsPageState(); } } class _MovieDetailsPageState extends ConsumerState { - final String id; - - _MovieDetailsPageState({required this.id}); @override Widget build(BuildContext context) { - var seriesDetails = ref.watch(mediaDetailsProvider(id)); - var torrents = ref.watch(movieTorrentsDataProvider(id)); + var seriesDetails = ref.watch(mediaDetailsProvider(widget.id)); + var torrents = ref.watch(movieTorrentsDataProvider(widget.id)); var storage = ref.watch(storageSettingProvider); return seriesDetails.when( @@ -107,7 +104,7 @@ class _MovieDetailsPageState extends ConsumerState { onPressed: () { ref .read( - mediaDetailsProvider(id).notifier) + mediaDetailsProvider(widget.id).notifier) .delete(); context.go(MovieDetailsPage.route); }, @@ -142,7 +139,7 @@ class _MovieDetailsPageState extends ConsumerState { icon: const Icon(Icons.download), onPressed: () async { await ref - .read(movieTorrentsDataProvider(id) + .read(movieTorrentsDataProvider(widget.id) .notifier) .download(torrent.link!); }, diff --git a/ui/lib/providers/welcome_data.dart b/ui/lib/providers/welcome_data.dart index 5722236..9cd82d3 100644 --- a/ui/lib/providers/welcome_data.dart +++ b/ui/lib/providers/welcome_data.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quiver/strings.dart'; import 'package:ui/providers/APIs.dart'; import 'package:ui/providers/server_response.dart'; @@ -29,18 +30,37 @@ final movieWatchlistDataProvider = FutureProvider.autoDispose((ref) async { }); var searchPageDataProvider = - AsyncNotifierProvider.autoDispose>( + AsyncNotifierProvider.autoDispose.family, String>( SearchPageData.new); var movieTorrentsDataProvider = AsyncNotifierProvider.autoDispose .family, String>( MovieTorrentResource.new); -class SearchPageData extends AutoDisposeAsyncNotifier> { +class SearchPageData + extends AutoDisposeFamilyAsyncNotifier, String> { List list = List.empty(growable: true); @override - FutureOr> build() async { + FutureOr> build(String arg) async { + if (isBlank(arg)) { + return List.empty(); + } + list = List.empty(growable: true); + final dio = await APIs.getDio(); + var resp = await dio.get(APIs.searchUrl, queryParameters: {"query": arg}); + + var rsp = ServerResponse.fromJson(resp.data as Map); + if (rsp.code != 0) { + throw rsp.message; + } + + var data = rsp.data as Map; + var results = data["results"] as List; + for (final r in results) { + var res = SearchResult.fromJson(r); + list.add(res); + } return list; } @@ -68,28 +88,8 @@ class SearchPageData extends AutoDisposeAsyncNotifier> { if (sp.code != 0) { throw sp.message; } - ref.invalidate(movieWatchlistDataProvider); } } - - Future queryResults(String q) async { - list = List.empty(growable: true); - final dio = await APIs.getDio(); - var resp = await dio.get(APIs.searchUrl, queryParameters: {"query": q}); - - var rsp = ServerResponse.fromJson(resp.data as Map); - if (rsp.code != 0) { - throw rsp.message; - } - - var data = rsp.data as Map; - var results = data["results"] as List; - for (final r in results) { - var res = SearchResult.fromJson(r); - list.add(res); - } - ref.invalidateSelf(); - } } class MediaDetail { diff --git a/ui/lib/search.dart b/ui/lib/search.dart index a34895b..1365166 100644 --- a/ui/lib/search.dart +++ b/ui/lib/search.dart @@ -1,14 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; import 'package:ui/providers/APIs.dart'; import 'package:ui/providers/settings.dart'; import 'package:ui/providers/welcome_data.dart'; import 'package:ui/widgets/progress_indicator.dart'; class SearchPage extends ConsumerStatefulWidget { - const SearchPage({super.key}); + const SearchPage({super.key, this.query}); static const route = "/search"; + final String? query; @override ConsumerState createState() { @@ -22,7 +24,8 @@ class _SearchPageState extends ConsumerState { Future? _pendingFuture; @override Widget build(BuildContext context) { - var searchList = ref.watch(searchPageDataProvider); + final q = widget.query??""; + var searchList = ref.watch(searchPageDataProvider(q)); List res = searchList.when( data: (data) { @@ -66,8 +69,14 @@ class _SearchPageState extends ConsumerState { width: 10, ), item.mediaType == "tv" - ? const Chip(avatar: Icon(Icons.live_tv),label: Text("电视剧",)) - : const Chip(avatar: Icon(Icons.movie),label: Text("电影")) + ? const Chip( + avatar: Icon(Icons.live_tv), + label: Text( + "电视剧", + )) + : const Chip( + avatar: Icon(Icons.movie), + label: Text("电影")) ], ), const Text(""), @@ -103,12 +112,11 @@ class _SearchPageState extends ConsumerState { children: [ TextField( autofocus: true, + controller: TextEditingController(text: q), onSubmitted: (value) async { - var f = - ref.read(searchPageDataProvider.notifier).queryResults(value); - setState(() { - _pendingFuture = f; - }); + context.go( + Uri(path: SearchPage.route, queryParameters: {'query': value}) + .toString()); }, decoration: const InputDecoration( labelText: "搜索", @@ -185,9 +193,8 @@ class _SearchPageState extends ConsumerState { ), child: const Text('确定'), onPressed: () { - print(storageSelected); ref - .read(searchPageDataProvider.notifier) + .read(searchPageDataProvider(widget.query??"").notifier) .submit2Watchlist(item.id!, storageSelected, resSelected, item.mediaType!); Navigator.of(context).pop(); diff --git a/ui/lib/tv_details.dart b/ui/lib/tv_details.dart index dcde099..22f50c4 100644 --- a/ui/lib/tv_details.dart +++ b/ui/lib/tv_details.dart @@ -21,14 +21,11 @@ class TvDetailsPage extends ConsumerStatefulWidget { @override ConsumerState createState() { - return _TvDetailsPageState(seriesId: seriesId); + return _TvDetailsPageState(); } } class _TvDetailsPageState extends ConsumerState { - final String seriesId; - - _TvDetailsPageState({required this.seriesId}); Future? _pendingFuture; @override @@ -38,7 +35,7 @@ class _TvDetailsPageState extends ConsumerState { @override Widget build(BuildContext context) { - var seriesDetails = ref.watch(mediaDetailsProvider(seriesId)); + var seriesDetails = ref.watch(mediaDetailsProvider(widget.seriesId)); var storage = ref.watch(storageSettingProvider); return FutureBuilder( // We listen to the pending operation, to update the UI accordingly. @@ -70,8 +67,8 @@ class _TvDetailsPageState extends ConsumerState { onPressed: () async { var f = ref .read( - mediaDetailsProvider(seriesId).notifier) - .searchAndDownload(seriesId, ep.seasonNumber!, + mediaDetailsProvider(widget.seriesId).notifier) + .searchAndDownload(widget.seriesId, ep.seasonNumber!, ep.episodeNumber!); setState(() { _pendingFuture = f; @@ -187,7 +184,7 @@ class _TvDetailsPageState extends ConsumerState { onPressed: () { ref .read(mediaDetailsProvider( - seriesId) + widget.seriesId) .notifier) .delete(); context.go(WelcomePage.routeTv);