From 33cb7947d63d0a2692a004f87a2ccd5777bf054e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 11 May 2023 23:50:17 +0600 Subject: [PATCH] feat: newly released albums of user followed artist --- lib/components/library/user_artists.dart | 32 ++++----------- lib/pages/home/personalized.dart | 50 ++++++++++++++---------- lib/services/queries/album.dart | 2 +- lib/services/queries/artist.dart | 26 ++++++++++++ 4 files changed, 65 insertions(+), 45 deletions(-) diff --git a/lib/components/library/user_artists.dart b/lib/components/library/user_artists.dart index e22c4d50b..7266e4061 100644 --- a/lib/components/library/user_artists.dart +++ b/lib/components/library/user_artists.dart @@ -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((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(), ), ), ), diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 8e35a18bf..ff8549d99 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -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>? playlists; - final Iterable>? albums; + final Iterable? playlists; + final Iterable? 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.empty(), - ) - .toList(); - - final albumItems = albums - ?.expand( - (page) => page.items ?? const Iterable.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>() + .expand((page) => page.items ?? const []), + [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>() + .expand((page) => page.items ?? const []) + .where((album) { + return album.artists + ?.any((artist) => userArtists.contains(artist.id!)) == + true; + }), + [newReleases.pages], + ); return ListView( children: [ PersonalizedItemCard( - playlists: - featuredPlaylistsQuery.pages.whereType>(), + playlists: playlists, title: context.l10n.featured, hasNextPage: featuredPlaylistsQuery.hasNextPage, onFetchMore: featuredPlaylistsQuery.fetchNext, ), PersonalizedItemCard( - albums: newReleases.pages.whereType>(), + albums: albums, title: context.l10n.new_releases, hasNextPage: newReleases.hasNextPage, onFetchMore: newReleases.fetchNext, diff --git a/lib/services/queries/album.dart b/lib/services/queries/album.dart index 27c1e483a..d4ffa2f51 100644 --- a/lib/services/queries/album.dart +++ b/lib/services/queries/album.dart @@ -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) { diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index fed55429e..27a58572a 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -38,6 +38,32 @@ class ArtistQueries { ); } + Query, dynamic> followedByMeAll(WidgetRef ref) { + return useSpotifyQuery( + "user-following-artists-all", + (spotify) async { + CursorPage? page = + await spotify.me.following(FollowingType.artist).getPage(50); + + final following = []; + + 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 doIFollow( WidgetRef ref, String artist,