Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit e160d4f561ff2e945fd67bf12b223c012da58b1e
Author: Kingkor Roy Tirtho <[email protected]>
Date:   Sat Sep 14 10:48:08 2024 +0600

    fix: pagination issues in playlist and album pages
  • Loading branch information
KRTirtho committed Sep 14, 2024
1 parent 40bfcc1 commit 3afe3ce
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 109 deletions.
103 changes: 51 additions & 52 deletions lib/components/tracks_view/sections/body/track_view_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,56 @@ class TrackViewBodySection extends HookConsumerWidget {

final isActive = playlist.collections.contains(props.collectionId);

final onTapTrackTile = useCallback((Track track, int index) async {
if (trackViewState.isSelecting) {
trackViewState.toggleTrackSelection(track.id!);
return;
}

final isRemoteDevice = await showSelectDeviceDialog(context, ref);

if (isRemoteDevice) {
final remotePlayback = ref.read(connectProvider.notifier);
final remoteQueue = ref.read(queueProvider);
if (remoteQueue.collections.contains(props.collectionId) ||
remoteQueue.tracks.any((s) => s.id == track.id)) {
await playlistNotifier.jumpToTrack(track);
} else {
final tracks = await props.pagination.onFetchAll();
await remotePlayback.load(
props.collection is AlbumSimple
? WebSocketLoadEventData.album(
tracks: tracks,
collection: props.collection as AlbumSimple,
initialIndex: index,
)
: WebSocketLoadEventData.playlist(
tracks: tracks,
collection: props.collection as PlaylistSimple,
initialIndex: index,
),
);
}
} else {
if (isActive || playlist.tracks.contains(track)) {
await playlistNotifier.jumpToTrack(track);
} else {
final tracks = await props.pagination.onFetchAll();
await playlistNotifier.load(
tracks,
initialIndex: index,
autoPlay: true,
);
playlistNotifier.addCollection(props.collectionId);
if (props.collection is AlbumSimple) {
historyNotifier.addAlbums([props.collection as AlbumSimple]);
} else {
historyNotifier.addPlaylists([props.collection as PlaylistSimple]);
}
}
}
}, [isActive, playlist, props, playlistNotifier, historyNotifier]);

return SliverMainAxisGroup(
slivers: [
SliverToBoxAdapter(
Expand Down Expand Up @@ -130,58 +180,7 @@ class TrackViewBodySection extends HookConsumerWidget {
trackViewState.selectTrack(track.id!);
HapticFeedback.selectionClick();
},
onTap: () async {
if (trackViewState.isSelecting) {
trackViewState.toggleTrackSelection(track.id!);
return;
}

final isRemoteDevice =
await showSelectDeviceDialog(context, ref);

if (isRemoteDevice) {
final remotePlayback = ref.read(connectProvider.notifier);
final remoteQueue = ref.read(queueProvider);
if (remoteQueue.collections.contains(props.collectionId) ||
remoteQueue.tracks.any((s) => s.id == track.id)) {
await playlistNotifier.jumpToTrack(track);
} else {
final tracks = await props.pagination.onFetchAll();
await remotePlayback.load(
props.collection is AlbumSimple
? WebSocketLoadEventData.album(
tracks: tracks,
collection: props.collection as AlbumSimple,
initialIndex: index,
)
: WebSocketLoadEventData.playlist(
tracks: tracks,
collection: props.collection as PlaylistSimple,
initialIndex: index,
),
);
}
} else {
if (isActive || playlist.tracks.contains(track)) {
await playlistNotifier.jumpToTrack(track);
} else {
final tracks = await props.pagination.onFetchAll();
await playlistNotifier.load(
tracks,
initialIndex: index,
autoPlay: true,
);
playlistNotifier.addCollection(props.collectionId);
if (props.collection is AlbumSimple) {
historyNotifier
.addAlbums([props.collection as AlbumSimple]);
} else {
historyNotifier
.addPlaylists([props.collection as PlaylistSimple]);
}
}
}
},
onTap: () => onTapTrackTile(track, index),
);
},
),
Expand Down
14 changes: 10 additions & 4 deletions lib/provider/history/top/albums.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,18 @@ class HistoryTopAlbumsNotifier extends FamilyPaginatedAsyncNotifier<
fetch(arg, offset, limit) async {
final albumsQuery = createAlbumsQuery(limit: limit, offset: offset);

return getAlbumsWithCount(await albumsQuery.get());
final items = getAlbumsWithCount(await albumsQuery.get());

return (
items: items,
hasMore: items.length == limit,
nextOffset: offset + limit,
);
}

@override
build(arg) async {
final albums = await fetch(arg, 0, 20);
final (items: albums, :hasMore, :nextOffset) = await fetch(arg, 0, 20);

final subscription = createAlbumsQuery().watch().listen((event) {
if (state.asData == null) return;
Expand All @@ -111,9 +117,9 @@ class HistoryTopAlbumsNotifier extends FamilyPaginatedAsyncNotifier<

return HistoryTopAlbumsState(
items: albums,
offset: albums.length,
offset: nextOffset,
limit: 20,
hasMore: true,
hasMore: hasMore,
);
}

Expand Down
14 changes: 10 additions & 4 deletions lib/provider/history/top/playlists.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ class HistoryTopPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<
fetch(arg, offset, limit) async {
final playlistsQuery = createPlaylistsQuery()..limit(limit, offset: offset);

return getPlaylistsWithCount(await playlistsQuery.get());
final items = getPlaylistsWithCount(await playlistsQuery.get());

return (
items: items,
hasMore: items.length == limit,
nextOffset: offset + limit,
);
}

@override
build(arg) async {
final playlists = await fetch(arg, 0, 20);
final (items: playlists, :hasMore, :nextOffset) = await fetch(arg, 0, 20);

final subscription = createPlaylistsQuery().watch().listen((event) {
if (state.asData == null) return;
Expand All @@ -76,9 +82,9 @@ class HistoryTopPlaylistsNotifier extends FamilyPaginatedAsyncNotifier<

return HistoryTopPlaylistsState(
items: playlists,
offset: playlists.length,
offset: nextOffset,
limit: 20,
hasMore: true,
hasMore: hasMore,
);
}

Expand Down
14 changes: 10 additions & 4 deletions lib/provider/history/top/tracks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,18 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<
fetch(arg, offset, limit) async {
final tracksQuery = createTracksQuery()..limit(limit, offset: offset);

return getTracksWithCount(await tracksQuery.get());
final items = getTracksWithCount(await tracksQuery.get());

return (
items: items,
hasMore: items.length == limit,
nextOffset: offset + limit,
);
}

@override
build(arg) async {
final tracks = await fetch(arg, 0, 20);
final (items: tracks, :hasMore, :nextOffset) = await fetch(arg, 0, 20);

final subscription = createTracksQuery().watch().listen((event) {
if (state.asData == null) return;
Expand All @@ -110,9 +116,9 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<

return HistoryTopTracksState(
items: tracks,
offset: tracks.length,
offset: nextOffset,
limit: 20,
hasMore: true,
hasMore: hasMore,
);
}

Expand Down
16 changes: 11 additions & 5 deletions lib/provider/spotify/album/tracks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,26 @@ class AlbumTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<Track,
@override
fetch(arg, offset, limit) async {
final tracks = await spotify.albums.tracks(arg.id!).getPage(limit, offset);
return tracks.items?.map((e) => e.asTrack(arg)).toList() ?? [];
final items = tracks.items?.map((e) => e.asTrack(arg)).toList() ?? [];

return (
items: items,
hasMore: !tracks.isLast,
nextOffset: tracks.nextOffset,
);
}

@override
build(arg) async {
ref.cacheFor();

ref.watch(spotifyProvider);
final tracks = await fetch(arg, 0, 20);
final (:items, :nextOffset, :hasMore) = await fetch(arg, 0, 20);
return AlbumTracksState(
items: tracks,
offset: 0,
items: items,
offset: nextOffset,
limit: 20,
hasMore: tracks.length == 20,
hasMore: hasMore,
);
}
}
Expand Down
16 changes: 11 additions & 5 deletions lib/provider/spotify/artist/albums.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ class ArtistAlbumsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
.albums(arg, country: market)
.getPage(limit, offset);

return albums.items?.toList() ?? [];
final items = albums.items?.toList() ?? [];

return (
items: items,
hasMore: !albums.isLast,
nextOffset: albums.nextOffset,
);
}

@override
Expand All @@ -46,12 +52,12 @@ class ArtistAlbumsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
ref.watch(
userPreferencesProvider.select((s) => s.market),
);
final albums = await fetch(arg, 0, 20);
final (:items, :hasMore, :nextOffset) = await fetch(arg, 0, 20);
return ArtistAlbumsState(
items: albums,
offset: 0,
items: items,
offset: nextOffset,
limit: 20,
hasMore: albums.length == 20,
hasMore: hasMore,
);
}
}
Expand Down
16 changes: 11 additions & 5 deletions lib/provider/spotify/category/playlists.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ class CategoryPlaylistsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
(json) => PlaylistsFeatured.fromJson(json),
).getPage(limit, offset);

return playlists.items?.whereNotNull().toList() ?? [];
final items = playlists.items?.whereNotNull().toList() ?? [];

return (
items: items,
hasMore: !playlists.isLast,
nextOffset: playlists.nextOffset,
);
}

@override
Expand All @@ -50,13 +56,13 @@ class CategoryPlaylistsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
ref.watch(userPreferencesProvider.select((s) => s.locale));
ref.watch(userPreferencesProvider.select((s) => s.market));

final playlists = await fetch(arg, 0, 8);
final (:items, :hasMore, :nextOffset) = await fetch(arg, 0, 8);

return CategoryPlaylistsState(
items: playlists,
offset: 0,
items: items,
offset: nextOffset,
limit: 8,
hasMore: playlists.length == 8,
hasMore: hasMore,
);
}
}
Expand Down
14 changes: 10 additions & 4 deletions lib/provider/spotify/playlist/tracks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,30 @@ class PlaylistTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<

/// Filter out tracks with null id because some personal playlists
/// may contain local tracks that are not available in the Spotify catalog
return tracks.items
final items = tracks.items
?.where((track) => track.id != null && track.type == "track")
.toList() ??
<Track>[];

return (
items: items,
hasMore: !tracks.isLast,
nextOffset: tracks.nextOffset,
);
}

@override
build(arg) async {
ref.cacheFor();

ref.watch(spotifyProvider);
final tracks = await fetch(arg, 0, 20);
final (items: tracks, :hasMore, :nextOffset) = await fetch(arg, 0, 20);

return PlaylistTracksState(
items: tracks,
offset: 0,
offset: nextOffset,
limit: 20,
hasMore: tracks.length == 20,
hasMore: hasMore,
);
}
}
Expand Down
24 changes: 18 additions & 6 deletions lib/provider/spotify/search/search.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ class SearchNotifier<Y> extends AutoDisposeFamilyPaginatedAsyncNotifier<Y,

@override
fetch(arg, offset, limit) async {
if (state.value == null) return [];
if (state.value == null) {
return (
items: <Y>[],
hasMore: false,
nextOffset: 0,
);
}
final results = await spotify.search
.get(
ref.read(searchTermStateProvider),
Expand All @@ -46,7 +52,13 @@ class SearchNotifier<Y> extends AutoDisposeFamilyPaginatedAsyncNotifier<Y,
)
.getPage(limit, offset);

return results.expand((e) => e.items ?? <Y>[]).toList().cast<Y>();
final items = results.expand((e) => e.items ?? <Y>[]).toList().cast<Y>();

return (
items: items,
hasMore: items.length == limit,
nextOffset: offset + limit,
);
}

@override
Expand All @@ -59,13 +71,13 @@ class SearchNotifier<Y> extends AutoDisposeFamilyPaginatedAsyncNotifier<Y,
userPreferencesProvider.select((value) => value.market),
);

final results = await fetch(arg, 0, 10);
final (:items, :hasMore, :nextOffset) = await fetch(arg, 0, 10);

return SearchState<Y>(
items: results,
offset: 0,
items: items,
offset: nextOffset,
limit: 10,
hasMore: results.length == 10,
hasMore: hasMore,
);
}
}
Expand Down
Loading

0 comments on commit 3afe3ce

Please sign in to comment.