mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-09 00:34:36 +00:00
feat: use provider in search page
This commit is contained in:
parent
25badae7ad
commit
b76e265f23
@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
@ -16,19 +17,19 @@ import 'package:spotube/pages/search/sections/artists.dart';
|
|||||||
import 'package:spotube/pages/search/sections/playlists.dart';
|
import 'package:spotube/pages/search/sections/playlists.dart';
|
||||||
import 'package:spotube/pages/search/sections/tracks.dart';
|
import 'package:spotube/pages/search/sections/tracks.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
final searchTermStateProvider = StateProvider<String>((ref) => "");
|
|
||||||
|
|
||||||
class SearchPage extends HookConsumerWidget {
|
class SearchPage extends HookConsumerWidget {
|
||||||
const SearchPage({super.key});
|
const SearchPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final controller = useTextEditingController();
|
||||||
|
|
||||||
ref.watch(AuthenticationNotifier.provider);
|
ref.watch(AuthenticationNotifier.provider);
|
||||||
final authenticationNotifier =
|
final authenticationNotifier =
|
||||||
ref.watch(AuthenticationNotifier.provider.notifier);
|
ref.watch(AuthenticationNotifier.provider.notifier);
|
||||||
@ -36,39 +37,14 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final searchTerm = ref.watch(searchTermStateProvider);
|
final searchTerm = ref.watch(searchTermStateProvider);
|
||||||
|
|
||||||
final searchTrack =
|
final searchTrack = ref.watch(searchProvider(SearchType.track));
|
||||||
useQueries.search.query(ref, searchTerm, SearchType.track);
|
final searchAlbum = ref.watch(searchProvider(SearchType.album));
|
||||||
final searchAlbum =
|
final searchPlaylist = ref.watch(searchProvider(SearchType.playlist));
|
||||||
useQueries.search.query(ref, searchTerm, SearchType.album);
|
final searchArtist = ref.watch(searchProvider(SearchType.artist));
|
||||||
final searchPlaylist =
|
|
||||||
useQueries.search.query(ref, searchTerm, SearchType.playlist);
|
|
||||||
final searchArtist =
|
|
||||||
useQueries.search.query(ref, searchTerm, SearchType.artist);
|
|
||||||
|
|
||||||
Future<void> onSearch() async {
|
|
||||||
await Future.wait([
|
|
||||||
searchTrack.reset(),
|
|
||||||
searchAlbum.reset(),
|
|
||||||
searchPlaylist.reset(),
|
|
||||||
searchArtist.reset(),
|
|
||||||
]).then((_) {
|
|
||||||
return Future.wait([
|
|
||||||
searchTrack.refreshAll(),
|
|
||||||
searchAlbum.refreshAll(),
|
|
||||||
searchPlaylist.refreshAll(),
|
|
||||||
searchArtist.refreshAll(),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final queries = [searchTrack, searchAlbum, searchPlaylist, searchArtist];
|
final queries = [searchTrack, searchAlbum, searchPlaylist, searchArtist];
|
||||||
final isFetching = queries.every(
|
|
||||||
(s) =>
|
final isFetching = queries.every((s) => s.isLoading);
|
||||||
(!s.hasPageData && !s.hasPageError) ||
|
|
||||||
s.isRefreshingPage ||
|
|
||||||
!s.hasPageData,
|
|
||||||
) &&
|
|
||||||
searchTerm.isNotEmpty;
|
|
||||||
|
|
||||||
final resultWidget = HookBuilder(
|
final resultWidget = HookBuilder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@ -78,18 +54,18 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
controller: controller,
|
controller: controller,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: Padding(
|
child: const Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SearchTracksSection(query: searchTrack),
|
SearchTracksSection(),
|
||||||
SearchPlaylistsSection(query: searchPlaylist),
|
SearchPlaylistsSection(),
|
||||||
const SizedBox(height: 20),
|
Gap(20),
|
||||||
SearchArtistsSection(query: searchArtist),
|
SearchArtistsSection(),
|
||||||
const SizedBox(height: 20),
|
Gap(20),
|
||||||
SearchAlbumsSection(query: searchAlbum),
|
SearchAlbumsSection(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -114,21 +90,22 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
color: theme.scaffoldBackgroundColor,
|
color: theme.scaffoldBackgroundColor,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
autofocus: queries
|
controller: controller,
|
||||||
.none((s) => s.hasPageData && !s.hasPageError) &&
|
autofocus:
|
||||||
|
queries.none((s) => s.value != null && !s.hasError) &&
|
||||||
!kIsMobile,
|
!kIsMobile,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(SpotubeIcons.search),
|
prefixIcon: const Icon(SpotubeIcons.search),
|
||||||
hintText: "${context.l10n.search}...",
|
hintText: "${context.l10n.search}...",
|
||||||
),
|
),
|
||||||
onSubmitted: (value) async {
|
onSubmitted: (value) async {
|
||||||
|
Timer(
|
||||||
|
const Duration(milliseconds: 50),
|
||||||
|
() {
|
||||||
ref.read(searchTermStateProvider.notifier).state =
|
ref.read(searchTermStateProvider.notifier).state =
|
||||||
value;
|
value;
|
||||||
// Fl-Query is too fast, so we need to delay the search
|
},
|
||||||
// to prevent spamming the API :)
|
);
|
||||||
Timer(const Duration(milliseconds: 50), () {
|
|
||||||
onSearch();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@ -7,33 +5,33 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
class SearchAlbumsSection extends HookConsumerWidget {
|
class SearchAlbumsSection extends HookConsumerWidget {
|
||||||
final InfiniteQuery<List<Page<dynamic>>, dynamic, int> query;
|
|
||||||
const SearchAlbumsSection({
|
const SearchAlbumsSection({
|
||||||
required this.query,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
|
final query = ref.watch(searchProvider(SearchType.album));
|
||||||
|
final notifier = ref.watch(searchProvider(SearchType.album).notifier);
|
||||||
final albums = useMemoized(
|
final albums = useMemoized(
|
||||||
() => query.pages
|
() =>
|
||||||
.expand(
|
query.value?.items
|
||||||
(page) => page.map((p) => p.items!).expand((element) => element),
|
.cast<AlbumSimple>()
|
||||||
)
|
.map(TypeConversionUtils.simpleAlbum_X_Album)
|
||||||
.whereType<AlbumSimple>()
|
.toList() ??
|
||||||
.map((e) => TypeConversionUtils.simpleAlbum_X_Album(e))
|
[],
|
||||||
.toList(),
|
[query.value],
|
||||||
[query.pages],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return HorizontalPlaybuttonCardView(
|
return HorizontalPlaybuttonCardView(
|
||||||
isLoadingNextPage: query.isLoadingNextPage,
|
isLoadingNextPage: query.isLoadingNextPage,
|
||||||
hasNextPage: query.hasNextPage,
|
hasNextPage: query.value?.hasMore == true,
|
||||||
items: albums,
|
items: albums,
|
||||||
onFetchMore: query.fetchNext,
|
onFetchMore: notifier.fetchMore,
|
||||||
title: Text(context.l10n.albums),
|
title: Text(context.l10n.albums),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,37 +1,28 @@
|
|||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class SearchArtistsSection extends HookConsumerWidget {
|
class SearchArtistsSection extends HookConsumerWidget {
|
||||||
final InfiniteQuery<List<Page<dynamic>>, dynamic, int> query;
|
|
||||||
|
|
||||||
const SearchArtistsSection({
|
const SearchArtistsSection({
|
||||||
super.key,
|
super.key,
|
||||||
required this.query,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final artists = useMemoized(
|
final query = ref.watch(searchProvider(SearchType.artist));
|
||||||
() => query.pages
|
final notifier = ref.watch(searchProvider(SearchType.artist).notifier);
|
||||||
.expand(
|
|
||||||
(page) => page.map((p) => p.items!).expand((element) => element),
|
final artists = query.value?.items.cast<Artist>() ?? [];
|
||||||
)
|
|
||||||
.whereType<Artist>()
|
|
||||||
.toList(),
|
|
||||||
[query.pages],
|
|
||||||
);
|
|
||||||
|
|
||||||
return HorizontalPlaybuttonCardView<Artist>(
|
return HorizontalPlaybuttonCardView<Artist>(
|
||||||
isLoadingNextPage: query.isLoadingNextPage,
|
isLoadingNextPage: query.isLoadingNextPage,
|
||||||
hasNextPage: query.hasNextPage,
|
hasNextPage: query.value?.hasMore == true,
|
||||||
items: artists,
|
items: artists,
|
||||||
onFetchMore: query.fetchNext,
|
onFetchMore: notifier.fetchMore,
|
||||||
title: Text(context.l10n.artists),
|
title: Text(context.l10n.artists),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,27 @@
|
|||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class SearchPlaylistsSection extends HookConsumerWidget {
|
class SearchPlaylistsSection extends HookConsumerWidget {
|
||||||
final InfiniteQuery<List<Page<dynamic>>, dynamic, int> query;
|
|
||||||
const SearchPlaylistsSection({
|
const SearchPlaylistsSection({
|
||||||
required this.query,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final playlists = useMemoized(
|
final playlistsQuery = ref.watch(searchProvider(SearchType.playlist));
|
||||||
() => query.pages
|
final playlistsQueryNotifier =
|
||||||
.expand(
|
ref.watch(searchProvider(SearchType.playlist).notifier);
|
||||||
(page) => page.map((p) => p.items!).expand((element) => element),
|
final playlists = playlistsQuery.value?.items.cast<PlaylistSimple>() ?? [];
|
||||||
)
|
|
||||||
.whereType<PlaylistSimple>()
|
|
||||||
.toList(),
|
|
||||||
[query.pages],
|
|
||||||
);
|
|
||||||
|
|
||||||
return HorizontalPlaybuttonCardView(
|
return HorizontalPlaybuttonCardView(
|
||||||
isLoadingNextPage: query.isLoadingNextPage,
|
isLoadingNextPage: playlistsQuery.isLoadingNextPage,
|
||||||
hasNextPage: query.hasNextPage,
|
hasNextPage: playlistsQuery.value?.hasMore == true,
|
||||||
items: playlists,
|
items: playlists,
|
||||||
onFetchMore: query.fetchNext,
|
onFetchMore: playlistsQueryNotifier.fetchMore,
|
||||||
title: Text(context.l10n.playlists),
|
title: Text(context.l10n.playlists),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +1,26 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
import 'package:flutter/material.dart' hide Page;
|
import 'package:flutter/material.dart' hide Page;
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/dialogs/prompt_dialog.dart';
|
import 'package:spotube/components/shared/dialogs/prompt_dialog.dart';
|
||||||
import 'package:spotube/components/shared/track_tile/track_tile.dart';
|
import 'package:spotube/components/shared/track_tile/track_tile.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class SearchTracksSection extends HookConsumerWidget {
|
class SearchTracksSection extends HookConsumerWidget {
|
||||||
final InfiniteQuery<List<Page<dynamic>>, dynamic, int> query;
|
|
||||||
const SearchTracksSection({
|
const SearchTracksSection({
|
||||||
super.key,
|
super.key,
|
||||||
required this.query,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final searchTrack = query;
|
final searchTrack = ref.watch(searchProvider(SearchType.track));
|
||||||
final tracks = useMemoized(
|
|
||||||
() => searchTrack.pages
|
final searchTrackNotifier =
|
||||||
.expand(
|
ref.watch(searchProvider(SearchType.track).notifier);
|
||||||
(page) => page.map((p) => p.items!).expand((element) => element),
|
|
||||||
)
|
final tracks = searchTrack.value?.items.cast<Track>() ?? [];
|
||||||
.whereType<Track>(),
|
|
||||||
[searchTrack.pages],
|
|
||||||
);
|
|
||||||
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.provider.notifier);
|
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.provider.notifier);
|
||||||
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
@ -43,14 +37,10 @@ class SearchTracksSection extends HookConsumerWidget {
|
|||||||
style: theme.textTheme.titleLarge!,
|
style: theme.textTheme.titleLarge!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!searchTrack.hasPageData &&
|
if (searchTrack.isLoadingAndEmpty)
|
||||||
!searchTrack.hasPageError &&
|
|
||||||
!searchTrack.isLoadingNextPage)
|
|
||||||
const CircularProgressIndicator()
|
const CircularProgressIndicator()
|
||||||
else if (searchTrack.hasPageError)
|
else if (searchTrack.hasError)
|
||||||
Text(
|
Text(searchTrack.error.toString())
|
||||||
searchTrack.errors.lastOrNull?.toString() ?? "",
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
...tracks.mapIndexed((i, track) {
|
...tracks.mapIndexed((i, track) {
|
||||||
return TrackTile(
|
return TrackTile(
|
||||||
@ -81,12 +71,12 @@ class SearchTracksSection extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
if (searchTrack.hasNextPage && tracks.isNotEmpty)
|
if (searchTrack.value?.hasMore == true && tracks.isNotEmpty)
|
||||||
Center(
|
Center(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: searchTrack.isLoadingNextPage
|
onPressed: searchTrack.isLoadingNextPage
|
||||||
? null
|
? null
|
||||||
: () => searchTrack.fetchNext(),
|
: () => searchTrackNotifier.fetchMore,
|
||||||
child: searchTrack.isLoadingNextPage
|
child: searchTrack.isLoadingNextPage
|
||||||
? const CircularProgressIndicator()
|
? const CircularProgressIndicator()
|
||||||
: Text(context.l10n.load_more),
|
: Text(context.l10n.load_more),
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
part of '../spotify.dart';
|
part of '../spotify.dart';
|
||||||
|
|
||||||
|
final searchTermStateProvider = StateProvider<String>((ref) => "");
|
||||||
|
|
||||||
class SearchState<Y> extends PaginatedState<Y> {
|
class SearchState<Y> extends PaginatedState<Y> {
|
||||||
final String query;
|
|
||||||
SearchState({
|
SearchState({
|
||||||
required super.items,
|
required super.items,
|
||||||
required super.offset,
|
required super.offset,
|
||||||
required super.limit,
|
required super.limit,
|
||||||
required super.hasMore,
|
required super.hasMore,
|
||||||
required this.query,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -16,14 +16,12 @@ class SearchState<Y> extends PaginatedState<Y> {
|
|||||||
int? offset,
|
int? offset,
|
||||||
int? limit,
|
int? limit,
|
||||||
bool? hasMore,
|
bool? hasMore,
|
||||||
String? query,
|
|
||||||
}) {
|
}) {
|
||||||
return SearchState(
|
return SearchState(
|
||||||
items: items ?? this.items,
|
items: items ?? this.items,
|
||||||
offset: offset ?? this.offset,
|
offset: offset ?? this.offset,
|
||||||
limit: limit ?? this.limit,
|
limit: limit ?? this.limit,
|
||||||
hasMore: hasMore ?? this.hasMore,
|
hasMore: hasMore ?? this.hasMore,
|
||||||
query: query ?? this.query,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,7 +35,7 @@ class SearchNotifier<Y>
|
|||||||
if (state.value == null) return [];
|
if (state.value == null) return [];
|
||||||
final results = await spotify.search
|
final results = await spotify.search
|
||||||
.get(
|
.get(
|
||||||
state.value!.query,
|
ref.read(searchTermStateProvider),
|
||||||
types: [arg],
|
types: [arg],
|
||||||
market: ref.read(userPreferencesProvider).recommendationMarket,
|
market: ref.read(userPreferencesProvider).recommendationMarket,
|
||||||
)
|
)
|
||||||
@ -48,6 +46,7 @@ class SearchNotifier<Y>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
build(arg) async {
|
build(arg) async {
|
||||||
|
ref.watch(searchTermStateProvider);
|
||||||
ref.watch(spotifyProvider);
|
ref.watch(spotifyProvider);
|
||||||
ref.watch(
|
ref.watch(
|
||||||
userPreferencesProvider.select((value) => value.recommendationMarket),
|
userPreferencesProvider.select((value) => value.recommendationMarket),
|
||||||
@ -60,30 +59,8 @@ class SearchNotifier<Y>
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
hasMore: results.length == 10,
|
hasMore: results.length == 10,
|
||||||
query: "",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> search(String query) async {
|
|
||||||
if (state.value == null) return;
|
|
||||||
|
|
||||||
state = AsyncData(
|
|
||||||
state.value!.copyWith(
|
|
||||||
query: query,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await update((state) async {
|
|
||||||
final results = await fetch(arg, 0, 10);
|
|
||||||
|
|
||||||
return state.copyWith(
|
|
||||||
items: results,
|
|
||||||
offset: 0,
|
|
||||||
limit: 10,
|
|
||||||
hasMore: results.length == 10,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final searchProvider =
|
final searchProvider =
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user