feat: change search behavior

This commit is contained in:
Simon Ding
2024-07-18 13:04:03 +08:00
parent 993dfd57f1
commit e26b21d03f
5 changed files with 73 additions and 60 deletions

View File

@@ -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,

View File

@@ -21,19 +21,16 @@ class MovieDetailsPage extends ConsumerStatefulWidget {
@override
ConsumerState<ConsumerStatefulWidget> createState() {
return _MovieDetailsPageState(id: id);
return _MovieDetailsPageState();
}
}
class _MovieDetailsPageState extends ConsumerState<MovieDetailsPage> {
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<MovieDetailsPage> {
onPressed: () {
ref
.read(
mediaDetailsProvider(id).notifier)
mediaDetailsProvider(widget.id).notifier)
.delete();
context.go(MovieDetailsPage.route);
},
@@ -142,7 +139,7 @@ class _MovieDetailsPageState extends ConsumerState<MovieDetailsPage> {
icon: const Icon(Icons.download),
onPressed: () async {
await ref
.read(movieTorrentsDataProvider(id)
.read(movieTorrentsDataProvider(widget.id)
.notifier)
.download(torrent.link!);
},

View File

@@ -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<SearchPageData, List<SearchResult>>(
AsyncNotifierProvider.autoDispose.family<SearchPageData, List<SearchResult>, String>(
SearchPageData.new);
var movieTorrentsDataProvider = AsyncNotifierProvider.autoDispose
.family<MovieTorrentResource, List<TorrentResource>, String>(
MovieTorrentResource.new);
class SearchPageData extends AutoDisposeAsyncNotifier<List<SearchResult>> {
class SearchPageData
extends AutoDisposeFamilyAsyncNotifier<List<SearchResult>, String> {
List<SearchResult> list = List.empty(growable: true);
@override
FutureOr<List<SearchResult>> build() async {
FutureOr<List<SearchResult>> 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<String, dynamic>);
if (rsp.code != 0) {
throw rsp.message;
}
var data = rsp.data as Map<String, dynamic>;
var results = data["results"] as List<dynamic>;
for (final r in results) {
var res = SearchResult.fromJson(r);
list.add(res);
}
return list;
}
@@ -68,28 +88,8 @@ class SearchPageData extends AutoDisposeAsyncNotifier<List<SearchResult>> {
if (sp.code != 0) {
throw sp.message;
}
ref.invalidate(movieWatchlistDataProvider);
}
}
Future<void> 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<String, dynamic>);
if (rsp.code != 0) {
throw rsp.message;
}
var data = rsp.data as Map<String, dynamic>;
var results = data["results"] as List<dynamic>;
for (final r in results) {
var res = SearchResult.fromJson(r);
list.add(res);
}
ref.invalidateSelf();
}
}
class MediaDetail {

View File

@@ -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<ConsumerStatefulWidget> createState() {
@@ -22,7 +24,8 @@ class _SearchPageState extends ConsumerState<SearchPage> {
Future<void>? _pendingFuture;
@override
Widget build(BuildContext context) {
var searchList = ref.watch(searchPageDataProvider);
final q = widget.query??"";
var searchList = ref.watch(searchPageDataProvider(q));
List<Widget> res = searchList.when(
data: (data) {
@@ -66,8 +69,14 @@ class _SearchPageState extends ConsumerState<SearchPage> {
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<SearchPage> {
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<SearchPage> {
),
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();

View File

@@ -21,14 +21,11 @@ class TvDetailsPage extends ConsumerStatefulWidget {
@override
ConsumerState<ConsumerStatefulWidget> createState() {
return _TvDetailsPageState(seriesId: seriesId);
return _TvDetailsPageState();
}
}
class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
final String seriesId;
_TvDetailsPageState({required this.seriesId});
Future<String>? _pendingFuture;
@override
@@ -38,7 +35,7 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
@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<TvDetailsPage> {
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<TvDetailsPage> {
onPressed: () {
ref
.read(mediaDetailsProvider(
seriesId)
widget.seriesId)
.notifier)
.delete();
context.go(WelcomePage.routeTv);