mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-08 16:24:36 +00:00
feat: use provider for playlist and album card and heart button
This commit is contained in:
parent
4ae530d29d
commit
25badae7ad
@ -1,15 +1,12 @@
|
|||||||
import 'package:fl_query_hooks/fl_query_hooks.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
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';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/playbutton_card.dart';
|
import 'package:spotube/components/shared/playbutton_card.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/extensions/infinite_query.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_provider.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||||
import 'package:spotube/services/queries/album.dart';
|
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
@ -31,15 +28,12 @@ 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();
|
|
||||||
|
|
||||||
bool isPlaylistPlaying = useMemoized(
|
bool isPlaylistPlaying = useMemoized(
|
||||||
() => playlist.containsCollection(album.id!),
|
() => playlist.containsCollection(album.id!),
|
||||||
[playlist, album.id],
|
[playlist, album.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
final updating = useState(false);
|
final updating = useState(false);
|
||||||
final spotify = ref.watch(spotifyProvider);
|
|
||||||
|
|
||||||
final scaffoldMessenger = ScaffoldMessenger.maybeOf(context);
|
final scaffoldMessenger = ScaffoldMessenger.maybeOf(context);
|
||||||
|
|
||||||
@ -50,23 +44,8 @@ class AlbumCard extends HookConsumerWidget {
|
|||||||
TypeConversionUtils.simpleTrack_X_Track(track, album))
|
TypeConversionUtils.simpleTrack_X_Track(track, album))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
final job = AlbumQueries.tracksOfJob(album.id!);
|
await ref.read(albumTracksProvider(album).future);
|
||||||
|
return ref.read(albumTracksProvider(album).notifier).fetchAll();
|
||||||
final query = queryClient.createInfiniteQuery(
|
|
||||||
job.queryKey,
|
|
||||||
(page) => job.task(page, (spotify: spotify, album: album)),
|
|
||||||
initialPage: 0,
|
|
||||||
nextPage: job.nextPage,
|
|
||||||
);
|
|
||||||
|
|
||||||
return await query.fetchAllTracks(
|
|
||||||
getAllTracks: () async {
|
|
||||||
final res = await spotify.albums.tracks(album.id!).all();
|
|
||||||
return res
|
|
||||||
.map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album))
|
|
||||||
.toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PlaybuttonCard(
|
return PlaybuttonCard(
|
||||||
|
|||||||
@ -34,7 +34,6 @@ class PlayerActions extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final mediaQuery = MediaQuery.of(context);
|
|
||||||
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
|
||||||
final isLocalTrack = playlist.activeTrack is LocalTrack;
|
final isLocalTrack = playlist.activeTrack is LocalTrack;
|
||||||
ref.watch(downloadManagerProvider);
|
ref.watch(downloadManagerProvider);
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
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';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/playbutton_card.dart';
|
import 'package:spotube/components/shared/playbutton_card.dart';
|
||||||
import 'package:spotube/extensions/infinite_query.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_provider.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
@ -24,7 +21,6 @@ class PlaylistCard extends HookConsumerWidget {
|
|||||||
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
|
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
|
||||||
final playing =
|
final playing =
|
||||||
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
|
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
|
||||||
final queryClient = QueryClient.of(context);
|
|
||||||
final tracks = useState<List<TrackSimple>?>(null);
|
final tracks = useState<List<TrackSimple>?>(null);
|
||||||
bool isPlaylistPlaying = useMemoized(
|
bool isPlaylistPlaying = useMemoized(
|
||||||
() => playlistQueue.containsCollection(playlist.id!),
|
() => playlistQueue.containsCollection(playlist.id!),
|
||||||
@ -32,32 +28,16 @@ class PlaylistCard extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final updating = useState(false);
|
final updating = useState(false);
|
||||||
final spotify = ref.watch(spotifyProvider);
|
final me = ref.watch(meProvider);
|
||||||
final me = useQueries.user.me(ref);
|
|
||||||
|
|
||||||
Future<List<Track>> fetchAllTracks() async {
|
Future<List<Track>> fetchAllTracks() async {
|
||||||
if (playlist.id == 'user-liked-tracks') {
|
if (playlist.id == 'user-liked-tracks') {
|
||||||
return await queryClient.fetchQuery(
|
return await ref.read(likedTracksProvider.future);
|
||||||
"user-liked-tracks",
|
|
||||||
() => useQueries.playlist.likedTracks(spotify),
|
|
||||||
) ??
|
|
||||||
[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final query = queryClient.createInfiniteQuery<List<Track>, dynamic, int>(
|
await ref.read(playlistTracksProvider(playlist.id!).future);
|
||||||
"playlist-tracks/${playlist.id}",
|
|
||||||
(page) => useQueries.playlist.tracksOf(page, spotify, playlist.id!),
|
|
||||||
initialPage: 0,
|
|
||||||
nextPage: useQueries.playlist.tracksOfQueryNextPage,
|
|
||||||
);
|
|
||||||
|
|
||||||
return await query.fetchAllTracks(
|
return ref.read(playlistTracksProvider(playlist.id!).notifier).fetchAll();
|
||||||
getAllTracks: () async {
|
|
||||||
final res =
|
|
||||||
await spotify.playlists.getTracksByPlaylistId(playlist.id!).all();
|
|
||||||
return res.toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PlaybuttonCard(
|
return PlaybuttonCard(
|
||||||
@ -71,7 +51,7 @@ class PlaylistCard extends HookConsumerWidget {
|
|||||||
isPlaying: isPlaylistPlaying,
|
isPlaying: isPlaylistPlaying,
|
||||||
isLoading:
|
isLoading:
|
||||||
(isPlaylistPlaying && playlistQueue.isFetching) || updating.value,
|
(isPlaylistPlaying && playlistQueue.isFetching) || updating.value,
|
||||||
isOwner: playlist.owner?.id == me.data?.id && me.data?.id != null,
|
isOwner: playlist.owner?.id == me.value?.id && me.value?.id != null,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(
|
ServiceUtils.push(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import 'package:fl_query/fl_query.dart';
|
|
||||||
import 'package:fl_query_hooks/fl_query_hooks.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
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';
|
||||||
@ -8,8 +6,7 @@ import 'package:spotify/spotify.dart';
|
|||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/provider/scrobbler_provider.dart';
|
import 'package:spotube/provider/scrobbler_provider.dart';
|
||||||
import 'package:spotube/services/mutations/mutations.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/services/queries/queries.dart';
|
|
||||||
|
|
||||||
class HeartButton extends HookConsumerWidget {
|
class HeartButton extends HookConsumerWidget {
|
||||||
final bool isLiked;
|
final bool isLiked;
|
||||||
@ -60,75 +57,32 @@ class HeartButton extends HookConsumerWidget {
|
|||||||
|
|
||||||
typedef UseTrackToggleLike = ({
|
typedef UseTrackToggleLike = ({
|
||||||
bool isLiked,
|
bool isLiked,
|
||||||
Mutation<bool, dynamic, bool> toggleTrackLike,
|
Future<void> Function(Track track) toggleTrackLike,
|
||||||
Query<User?, dynamic> me,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
UseTrackToggleLike useTrackToggleLike(Track track, WidgetRef ref) {
|
UseTrackToggleLike useTrackToggleLike(Track track, WidgetRef ref) {
|
||||||
final me = useQueries.user.me(ref);
|
final savedTracks = ref.watch(likedTracksProvider);
|
||||||
|
final savedTracksNotifier = ref.watch(likedTracksProvider.notifier);
|
||||||
final savedTracks = useQueries.playlist.likedTracksQuery(ref);
|
|
||||||
|
|
||||||
final isLiked = useMemoized(
|
final isLiked = useMemoized(
|
||||||
() => savedTracks.data?.any((element) => element.id == track.id) ?? false,
|
() => savedTracks.value?.any((element) => element.id == track.id) ?? false,
|
||||||
[savedTracks.data, track.id],
|
[savedTracks.value, track.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
final mounted = useIsMounted();
|
|
||||||
|
|
||||||
final scrobblerNotifier = ref.read(scrobblerProvider.notifier);
|
final scrobblerNotifier = ref.read(scrobblerProvider.notifier);
|
||||||
|
|
||||||
final toggleTrackLike = useMutations.track.toggleFavorite(
|
return (
|
||||||
ref,
|
isLiked: isLiked,
|
||||||
track.id!,
|
toggleTrackLike: (track) async {
|
||||||
onMutate: (isLiked) {
|
await savedTracksNotifier.toggleFavorite(track);
|
||||||
if (isLiked) {
|
|
||||||
savedTracks.setData(
|
if (!isLiked) {
|
||||||
savedTracks.data
|
|
||||||
?.where((element) => element.id != track.id)
|
|
||||||
.toList() ??
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
savedTracks.setData(
|
|
||||||
[
|
|
||||||
...?savedTracks.data,
|
|
||||||
track,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return isLiked;
|
|
||||||
},
|
|
||||||
onData: (isLiked, recoveryData) async {
|
|
||||||
await savedTracks.refresh();
|
|
||||||
if (isLiked) {
|
|
||||||
await scrobblerNotifier.love(track);
|
await scrobblerNotifier.love(track);
|
||||||
} else {
|
} else {
|
||||||
await scrobblerNotifier.unlove(track);
|
await scrobblerNotifier.unlove(track);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (payload, isLiked) {
|
|
||||||
if (!mounted()) return;
|
|
||||||
|
|
||||||
if (isLiked != true) {
|
|
||||||
savedTracks.setData(
|
|
||||||
savedTracks.data
|
|
||||||
?.where((element) => element.id != track.id)
|
|
||||||
.toList() ??
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
savedTracks.setData(
|
|
||||||
[
|
|
||||||
...?savedTracks.data,
|
|
||||||
track,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (isLiked: isLiked, toggleTrackLike: toggleTrackLike, me: me);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrackHeartButton extends HookConsumerWidget {
|
class TrackHeartButton extends HookConsumerWidget {
|
||||||
@ -140,10 +94,11 @@ class TrackHeartButton extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final savedTracks = useQueries.playlist.likedTracksQuery(ref);
|
final savedTracks = ref.watch(likedTracksProvider);
|
||||||
final (:me, :isLiked, :toggleTrackLike) = useTrackToggleLike(track, ref);
|
final me = ref.watch(meProvider);
|
||||||
|
final (:isLiked, :toggleTrackLike) = useTrackToggleLike(track, ref);
|
||||||
|
|
||||||
if (me.isLoading || !me.hasData) {
|
if (me.isLoading) {
|
||||||
return const CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,104 +107,9 @@ class TrackHeartButton extends HookConsumerWidget {
|
|||||||
? context.l10n.remove_from_favorites
|
? context.l10n.remove_from_favorites
|
||||||
: context.l10n.save_as_favorite,
|
: context.l10n.save_as_favorite,
|
||||||
isLiked: isLiked,
|
isLiked: isLiked,
|
||||||
onPressed: savedTracks.hasData
|
onPressed: savedTracks.value != null
|
||||||
? () {
|
? () {
|
||||||
toggleTrackLike.mutate(isLiked);
|
toggleTrackLike(track);
|
||||||
}
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PlaylistHeartButton extends HookConsumerWidget {
|
|
||||||
final PlaylistSimple playlist;
|
|
||||||
final IconData? icon;
|
|
||||||
final ValueChanged<bool>? onData;
|
|
||||||
|
|
||||||
const PlaylistHeartButton({
|
|
||||||
required this.playlist,
|
|
||||||
super.key,
|
|
||||||
this.icon,
|
|
||||||
this.onData,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, ref) {
|
|
||||||
final me = useQueries.user.me(ref);
|
|
||||||
|
|
||||||
final isLikedQuery = useQueries.playlist.doesUserFollow(
|
|
||||||
ref,
|
|
||||||
playlist.id!,
|
|
||||||
me.data?.id ?? '',
|
|
||||||
);
|
|
||||||
|
|
||||||
final togglePlaylistLike = useMutations.playlist.toggleFavorite(
|
|
||||||
ref,
|
|
||||||
playlist.id!,
|
|
||||||
refreshQueries: [
|
|
||||||
isLikedQuery.key,
|
|
||||||
],
|
|
||||||
onData: onData,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (me.isLoading || !me.hasData) {
|
|
||||||
return const CircularProgressIndicator();
|
|
||||||
}
|
|
||||||
|
|
||||||
return HeartButton(
|
|
||||||
isLiked: isLikedQuery.data ?? false,
|
|
||||||
tooltip: isLikedQuery.data ?? false
|
|
||||||
? context.l10n.remove_from_favorites
|
|
||||||
: context.l10n.save_as_favorite,
|
|
||||||
color: Colors.white,
|
|
||||||
icon: icon,
|
|
||||||
onPressed: isLikedQuery.hasData
|
|
||||||
? () {
|
|
||||||
togglePlaylistLike.mutate(isLikedQuery.data!);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AlbumHeartButton extends HookConsumerWidget {
|
|
||||||
final AlbumSimple album;
|
|
||||||
|
|
||||||
const AlbumHeartButton({
|
|
||||||
required this.album,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, ref) {
|
|
||||||
final client = useQueryClient();
|
|
||||||
final me = useQueries.user.me(ref);
|
|
||||||
|
|
||||||
final albumIsSaved = useQueries.album.isSavedForMe(ref, album.id!);
|
|
||||||
final isLiked = albumIsSaved.data ?? false;
|
|
||||||
|
|
||||||
final toggleAlbumLike = useMutations.album.toggleFavorite(
|
|
||||||
ref,
|
|
||||||
album.id!,
|
|
||||||
refreshQueries: [albumIsSaved.key],
|
|
||||||
onData: (_, __) async {
|
|
||||||
await client.refreshInfiniteQueryAllPages("current-user-albums");
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (me.isLoading || !me.hasData) {
|
|
||||||
return const CircularProgressIndicator();
|
|
||||||
}
|
|
||||||
|
|
||||||
return HeartButton(
|
|
||||||
isLiked: isLiked,
|
|
||||||
tooltip: isLiked
|
|
||||||
? context.l10n.remove_from_favorites
|
|
||||||
: context.l10n.save_as_favorite,
|
|
||||||
color: Colors.white,
|
|
||||||
onPressed: albumIsSaved.hasData
|
|
||||||
? () {
|
|
||||||
toggleAlbumLike.mutate(isLiked);
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import 'package:spotube/provider/authentication_provider.dart';
|
|||||||
import 'package:spotube/provider/blacklist_provider.dart';
|
import 'package:spotube/provider/blacklist_provider.dart';
|
||||||
import 'package:spotube/provider/download_manager_provider.dart';
|
import 'package:spotube/provider/download_manager_provider.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';
|
||||||
import 'package:spotube/provider/spotify_provider.dart';
|
import 'package:spotube/provider/spotify_provider.dart';
|
||||||
import 'package:spotube/services/mutations/mutations.dart';
|
import 'package:spotube/services/mutations/mutations.dart';
|
||||||
import 'package:spotube/services/queries/search.dart';
|
import 'package:spotube/services/queries/search.dart';
|
||||||
@ -176,6 +177,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
ref.watch(downloadManagerProvider);
|
ref.watch(downloadManagerProvider);
|
||||||
final downloadManager = ref.watch(downloadManagerProvider.notifier);
|
final downloadManager = ref.watch(downloadManagerProvider.notifier);
|
||||||
final blacklist = ref.watch(BlackListNotifier.provider);
|
final blacklist = ref.watch(BlackListNotifier.provider);
|
||||||
|
final me = ref.watch(meProvider);
|
||||||
|
|
||||||
final favorites = useTrackToggleLike(track, ref);
|
final favorites = useTrackToggleLike(track, ref);
|
||||||
|
|
||||||
@ -220,7 +222,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
break;
|
break;
|
||||||
case TrackOptionValue.delete:
|
case TrackOptionValue.delete:
|
||||||
await File((track as LocalTrack).path).delete();
|
await File((track as LocalTrack).path).delete();
|
||||||
ref.refresh(localTracksProvider);
|
ref.invalidate(localTracksProvider);
|
||||||
break;
|
break;
|
||||||
case TrackOptionValue.addToQueue:
|
case TrackOptionValue.addToQueue:
|
||||||
await playback.addTrack(track);
|
await playback.addTrack(track);
|
||||||
@ -257,7 +259,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TrackOptionValue.favorite:
|
case TrackOptionValue.favorite:
|
||||||
favorites.toggleTrackLike.mutate(favorites.isLiked);
|
favorites.toggleTrackLike(track);
|
||||||
break;
|
break;
|
||||||
case TrackOptionValue.addToPlaylist:
|
case TrackOptionValue.addToPlaylist:
|
||||||
actionAddToPlaylist(context, track);
|
actionAddToPlaylist(context, track);
|
||||||
@ -361,7 +363,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
leading: const Icon(SpotubeIcons.queueRemove),
|
leading: const Icon(SpotubeIcons.queueRemove),
|
||||||
title: Text(context.l10n.remove_from_queue),
|
title: Text(context.l10n.remove_from_queue),
|
||||||
),
|
),
|
||||||
if (favorites.me.hasData)
|
if (me.value != null)
|
||||||
PopSheetEntry(
|
PopSheetEntry(
|
||||||
value: TrackOptionValue.favorite,
|
value: TrackOptionValue.favorite,
|
||||||
leading: favorites.isLiked
|
leading: favorites.isLiked
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class LikedTracksNotifier extends AsyncNotifier<List<Track>> with Persistence {
|
|||||||
return tracks.where((e) => e.id != track.id).toList();
|
return tracks.where((e) => e.id != track.id).toList();
|
||||||
} else {
|
} else {
|
||||||
await spotify.tracks.me.saveOne(track.id!);
|
await spotify.tracks.me.saveOne(track.id!);
|
||||||
return [...tracks, track];
|
return [track, ...tracks];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user