fix: collection currently playing state persist on restart

This commit is contained in:
Kingkor Roy Tirtho 2023-06-20 11:55:23 +06:00
parent 9251121ba0
commit 1c89e3efb0
7 changed files with 46 additions and 11 deletions

View File

@ -46,11 +46,9 @@ class AlbumCard extends HookConsumerWidget {
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
final queryClient = useQueryClient(); final queryClient = useQueryClient();
final query = queryClient
.getQuery<List<TrackSimple>, dynamic>("album-tracks/${album.id}");
bool isPlaylistPlaying = useMemoized( bool isPlaylistPlaying = useMemoized(
() => playlist.containsTracks(query?.data ?? album.tracks ?? []), () => playlist.containsCollection(album.id!),
[playlistNotifier, query?.data, album.tracks], [playlist, album.id],
); );
final int marginH = final int marginH =
useBreakpointValue(xs: 10, sm: 10, md: 15, lg: 20, xl: 20, xxl: 20); useBreakpointValue(xs: 10, sm: 10, md: 15, lg: 20, xl: 20, xxl: 20);
@ -89,6 +87,7 @@ class AlbumCard extends HookConsumerWidget {
[], [],
autoPlay: true, autoPlay: true,
); );
playlistNotifier.addCollection(album.id!);
} finally { } finally {
updating.value = false; updating.value = false;
} }
@ -118,6 +117,7 @@ class AlbumCard extends HookConsumerWidget {
if (fetchedTracks == null || fetchedTracks.isEmpty) return; if (fetchedTracks == null || fetchedTracks.isEmpty) return;
playlistNotifier.addTracks(fetchedTracks); playlistNotifier.addTracks(fetchedTracks);
playlistNotifier.addCollection(album.id!);
if (context.mounted) { if (context.mounted) {
final snackbar = SnackBar( final snackbar = SnackBar(
content: Text("Added ${album.tracks?.length} tracks to queue"), content: Text("Added ${album.tracks?.length} tracks to queue"),

View File

@ -24,13 +24,10 @@ class PlaylistCard extends HookConsumerWidget {
final playing = final playing =
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
final queryBowl = QueryClient.of(context); final queryBowl = QueryClient.of(context);
final query = queryBowl.getQuery<List<Track>, dynamic>(
"playlist-tracks/${playlist.id}",
);
final tracks = useState<List<TrackSimple>?>(null); final tracks = useState<List<TrackSimple>?>(null);
bool isPlaylistPlaying = useMemoized( bool isPlaylistPlaying = useMemoized(
() => playlistQueue.containsTracks(tracks.value ?? query?.data ?? []), () => playlistQueue.containsCollection(playlist.id!),
[playlistNotifier, tracks.value, query?.data], [playlistQueue, playlist.id],
); );
final updating = useState(false); final updating = useState(false);
@ -72,6 +69,7 @@ class PlaylistCard extends HookConsumerWidget {
if (fetchedTracks.isEmpty) return; if (fetchedTracks.isEmpty) return;
await playlistNotifier.load(fetchedTracks, autoPlay: true); await playlistNotifier.load(fetchedTracks, autoPlay: true);
playlistNotifier.addCollection(playlist.id!);
tracks.value = fetchedTracks; tracks.value = fetchedTracks;
} finally { } finally {
updating.value = false; updating.value = false;
@ -90,6 +88,7 @@ class PlaylistCard extends HookConsumerWidget {
if (fetchedTracks.isEmpty) return; if (fetchedTracks.isEmpty) return;
playlistNotifier.addTracks(fetchedTracks); playlistNotifier.addTracks(fetchedTracks);
playlistNotifier.addCollection(playlist.id!);
tracks.value = fetchedTracks; tracks.value = fetchedTracks;
if (context.mounted) { if (context.mounted) {
final snackbar = SnackBar( final snackbar = SnackBar(

View File

@ -1,6 +1,5 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -219,6 +218,9 @@ class TracksTableView extends HookConsumerWidget {
case "play-next": case "play-next":
{ {
playback.addTracksAtFirst(selectedTracks); playback.addTracksAtFirst(selectedTracks);
if (playlistId != null) {
playback.addCollection(playlistId!);
}
selected.value = []; selected.value = [];
showCheck.value = false; showCheck.value = false;
break; break;
@ -226,6 +228,9 @@ class TracksTableView extends HookConsumerWidget {
case "add-to-queue": case "add-to-queue":
{ {
playback.addTracks(selectedTracks); playback.addTracks(selectedTracks);
if (playlistId != null) {
playback.addCollection(playlistId!);
}
selected.value = []; selected.value = [];
showCheck.value = false; showCheck.value = false;
break; break;

View File

@ -32,6 +32,7 @@ class AlbumPage extends HookConsumerWidget {
sortedTracks, sortedTracks,
initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id), initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id),
); );
playback.addCollection(album.id!);
} else if (isPlaylistPlaying && } else if (isPlaylistPlaying &&
currentTrack.id != null && currentTrack.id != null &&
currentTrack.id != playlist.activeTrack?.id) { currentTrack.id != playlist.activeTrack?.id) {
@ -101,6 +102,7 @@ class AlbumPage extends HookConsumerWidget {
TypeConversionUtils.simpleTrack_X_Track(track, album)) TypeConversionUtils.simpleTrack_X_Track(track, album))
.toList(), .toList(),
); );
playback.addCollection(album.id!);
} }
}, },
onShare: () { onShare: () {

View File

@ -36,6 +36,7 @@ class PlaylistView extends HookConsumerWidget {
initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id), initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id),
autoPlay: true, autoPlay: true,
); );
playback.addCollection(playlist.id!);
} else if (isPlaylistPlaying && } else if (isPlaylistPlaying &&
currentTrack.id != null && currentTrack.id != null &&
currentTrack.id != proxyPlaylist.activeTrack?.id) { currentTrack.id != proxyPlaylist.activeTrack?.id) {
@ -97,6 +98,7 @@ class PlaylistView extends HookConsumerWidget {
onAddToQueue: () { onAddToQueue: () {
if (tracksSnapshot.hasData && !isPlaylistPlaying) { if (tracksSnapshot.hasData && !isPlaylistPlaying) {
playlistNotifier.addTracks(tracksSnapshot.data!); playlistNotifier.addTracks(tracksSnapshot.data!);
playlistNotifier.addCollection(playlist.id!);
} }
}, },
bottomSpace: mediaQuery.mdAndDown, bottomSpace: mediaQuery.mdAndDown,

View File

@ -6,15 +6,20 @@ import 'package:spotube/models/spotube_track.dart';
class ProxyPlaylist { class ProxyPlaylist {
final Set<Track> tracks; final Set<Track> tracks;
final Set<String> collections;
final int? active; final int? active;
ProxyPlaylist(this.tracks, [this.active]); ProxyPlaylist(this.tracks, [this.active, this.collections = const {}]);
factory ProxyPlaylist.fromJson(Map<String, dynamic> json) { factory ProxyPlaylist.fromJson(Map<String, dynamic> json) {
return ProxyPlaylist( return ProxyPlaylist(
List.castFrom<dynamic, Map<String, dynamic>>( List.castFrom<dynamic, Map<String, dynamic>>(
json['tracks'] ?? <Map<String, dynamic>>[], json['tracks'] ?? <Map<String, dynamic>>[],
).map(_makeAppropriateTrack).toSet(), ).map(_makeAppropriateTrack).toSet(),
json['active'] as int?, json['active'] as int?,
json['collections'] == null
? {}
: (json['collections'] as List).toSet().cast<String>(),
); );
} }
@ -26,6 +31,10 @@ class ProxyPlaylist {
activeTrack is! SpotubeTrack && activeTrack is! SpotubeTrack &&
activeTrack is! LocalTrack; activeTrack is! LocalTrack;
bool containsCollection(String collection) {
return collections.contains(collection);
}
bool containsTrack(TrackSimple track) { bool containsTrack(TrackSimple track) {
return tracks.firstWhereOrNull((element) => element.id == track.id) != null; return tracks.firstWhereOrNull((element) => element.id == track.id) != null;
} }
@ -57,16 +66,19 @@ class ProxyPlaylist {
return { return {
'tracks': tracks.map(_makeAppropriateTrackJson).toList(), 'tracks': tracks.map(_makeAppropriateTrackJson).toList(),
'active': active, 'active': active,
'collections': collections.toList(),
}; };
} }
ProxyPlaylist copyWith({ ProxyPlaylist copyWith({
Set<Track>? tracks, Set<Track>? tracks,
int? active, int? active,
Set<String>? collections,
}) { }) {
return ProxyPlaylist( return ProxyPlaylist(
tracks ?? this.tracks, tracks ?? this.tracks,
active ?? this.active, active ?? this.active,
collections ?? this.collections,
); );
} }
} }

View File

@ -185,6 +185,19 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist>
} }
} }
void addCollection(String collectionId) {
state = state.copyWith(collections: {
...state.collections,
collectionId,
});
}
void removeCollection(String collectionId) {
state = state.copyWith(collections: {
...state.collections..remove(collectionId),
});
}
// TODO: Safely Remove playing tracks // TODO: Safely Remove playing tracks
Future<void> removeTrack(String trackId) async { Future<void> removeTrack(String trackId) async {
@ -224,6 +237,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist>
state = state.copyWith( state = state.copyWith(
tracks: tracks.toSet(), tracks: tracks.toSet(),
active: initialIndex, active: initialIndex,
collections: {},
); );
await notificationService.addTrack(indexTrack); await notificationService.addTrack(indexTrack);
} else { } else {
@ -236,6 +250,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist>
state = state.copyWith( state = state.copyWith(
tracks: mergeTracks([addableTrack], tracks), tracks: mergeTracks([addableTrack], tracks),
active: initialIndex, active: initialIndex,
collections: {},
); );
await notificationService.addTrack(addableTrack); await notificationService.addTrack(addableTrack);
await storeTrack( await storeTrack(