feat: newly released albums of user followed artist

This commit is contained in:
Kingkor Roy Tirtho 2023-05-11 23:50:17 +06:00
parent 38929fed6e
commit 33cb7947d6
4 changed files with 65 additions and 45 deletions

View File

@ -4,10 +4,8 @@ import 'package:collection/collection.dart';
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart';
import 'package:spotube/components/shared/waypoint.dart';
import 'package:spotube/components/artist/artist_card.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/authentication_provider.dart';
@ -22,17 +20,12 @@ class UserArtists extends HookConsumerWidget {
final theme = Theme.of(context);
final auth = ref.watch(AuthenticationNotifier.provider);
final artistQuery = useQueries.artist.followedByMe(ref);
final hasNextPage = artistQuery.pages.isEmpty
? false
: (artistQuery.pages.last.items?.length ?? 0) == 15;
final artistQuery = useQueries.artist.followedByMeAll(ref);
final searchText = useState('');
final filteredArtists = useMemoized(() {
final artists = artistQuery.pages
.expand<Artist>((page) => page.items ?? const Iterable.empty());
final artists = artistQuery.data ?? [];
if (searchText.value.isEmpty) {
return artists.toList();
@ -46,7 +39,7 @@ class UserArtists extends HookConsumerWidget {
.where((e) => e.item1 > 50)
.map((e) => e.item2)
.toList();
}, [artistQuery.pages, searchText.value]);
}, [artistQuery.data, searchText.value]);
final controller = useScrollController();
@ -72,7 +65,7 @@ class UserArtists extends HookConsumerWidget {
),
),
backgroundColor: theme.scaffoldBackgroundColor,
body: artistQuery.pages.isEmpty
body: artistQuery.data?.isEmpty == true
? Padding(
padding: const EdgeInsets.all(20),
child: Row(
@ -86,7 +79,7 @@ class UserArtists extends HookConsumerWidget {
)
: RefreshIndicator(
onRefresh: () async {
await artistQuery.refreshAll();
await artistQuery.refresh();
},
child: SingleChildScrollView(
controller: controller,
@ -97,18 +90,9 @@ class UserArtists extends HookConsumerWidget {
child: Wrap(
spacing: 15,
runSpacing: 5,
children: filteredArtists.mapIndexed((index, artist) {
if (index == artistQuery.pages.length - 1 &&
hasNextPage) {
return Waypoint(
controller: controller,
isGrid: true,
onTouchEdge: artistQuery.fetchNext,
child: ArtistCard(artist),
);
}
return ArtistCard(artist);
}).toList(),
children: filteredArtists
.mapIndexed((index, artist) => ArtistCard(artist))
.toList(),
),
),
),

View File

@ -14,8 +14,8 @@ import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
class PersonalizedItemCard extends HookWidget {
final Iterable<Page<PlaylistSimple>>? playlists;
final Iterable<Page<AlbumSimple>>? albums;
final Iterable<PlaylistSimple>? playlists;
final Iterable<AlbumSimple>? albums;
final String title;
final bool hasNextPage;
final void Function() onFetchMore;
@ -36,18 +36,6 @@ class PersonalizedItemCard extends HookWidget {
Widget build(BuildContext context) {
final scrollController = useScrollController();
final playlistItems = playlists
?.expand(
(page) => page.items ?? const Iterable<PlaylistSimple>.empty(),
)
.toList();
final albumItems = albums
?.expand(
(page) => page.items ?? const Iterable<AlbumSimple>.empty(),
)
.toList();
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
@ -82,9 +70,8 @@ class PersonalizedItemCard extends HookWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
...?playlistItems
?.map((playlist) => PlaylistCard(playlist)),
...?albumItems?.map(
...?playlists?.map((playlist) => PlaylistCard(playlist)),
...?albums?.map(
(album) => AlbumCard(
TypeConversionUtils.simpleAlbum_X_Album(album),
),
@ -108,20 +95,43 @@ class PersonalizedPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
final featuredPlaylistsQuery = useQueries.playlist.featured(ref);
final playlists = useMemoized(
() => featuredPlaylistsQuery.pages
.whereType<Page<PlaylistSimple>>()
.expand((page) => page.items ?? const <PlaylistSimple>[]),
[featuredPlaylistsQuery.pages],
);
final newReleases = useQueries.album.newReleases(ref);
final userArtists = useQueries.artist
.followedByMeAll(ref)
.data
?.map((s) => s.id!)
.toList() ??
const [];
final albums = useMemoized(
() => newReleases.pages
.whereType<Page<AlbumSimple>>()
.expand((page) => page.items ?? const <AlbumSimple>[])
.where((album) {
return album.artists
?.any((artist) => userArtists.contains(artist.id!)) ==
true;
}),
[newReleases.pages],
);
return ListView(
children: [
PersonalizedItemCard(
playlists:
featuredPlaylistsQuery.pages.whereType<Page<PlaylistSimple>>(),
playlists: playlists,
title: context.l10n.featured,
hasNextPage: featuredPlaylistsQuery.hasNextPage,
onFetchMore: featuredPlaylistsQuery.fetchNext,
),
PersonalizedItemCard(
albums: newReleases.pages.whereType<Page<AlbumSimple>>(),
albums: albums,
title: context.l10n.new_releases,
hasNextPage: newReleases.hasNextPage,
onFetchMore: newReleases.fetchNext,

View File

@ -58,7 +58,7 @@ class AlbumQueries {
try {
final albums = await spotify.browse
.getNewReleases(country: market)
.getPage(5, pageParam);
.getPage(50, pageParam);
return albums;
} catch (e, stack) {

View File

@ -38,6 +38,32 @@ class ArtistQueries {
);
}
Query<List<Artist>, dynamic> followedByMeAll(WidgetRef ref) {
return useSpotifyQuery(
"user-following-artists-all",
(spotify) async {
CursorPage<Artist>? page =
await spotify.me.following(FollowingType.artist).getPage(50);
final following = <Artist>[];
if (page.isLast == true) {
return page.items?.toList() ?? [];
}
while (page?.isLast != true) {
following.addAll(page?.items ?? []);
page = await spotify.me
.following(FollowingType.artist)
.getPage(50, page?.after ?? '');
}
return following;
},
ref: ref,
);
}
Query<bool, dynamic> doIFollow(
WidgetRef ref,
String artist,