diff --git a/lib/components/album/album_card.dart b/lib/components/album/album_card.dart index acdb266d9..2cf0b9e66 100644 --- a/lib/components/album/album_card.dart +++ b/lib/components/album/album_card.dart @@ -24,7 +24,8 @@ class AlbumCard extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final playlist = ref.watch(PlaylistQueueNotifier.provider); - final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; + final playing = useStream(PlaylistQueueNotifier.playing).data ?? + PlaylistQueueNotifier.isPlaying; final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); final queryBowl = QueryBowl.of(context); final query = queryBowl.getQuery, SpotifyApi>( @@ -33,6 +34,9 @@ class AlbumCard extends HookConsumerWidget { bool isPlaylistPlaying = playlistNotifier.isPlayingPlaylist(tracks.value); final int marginH = useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20); + + final updating = useState(false); + return PlaybuttonCard( imageUrl: TypeConversionUtils.image_X_UrlString( album.images, @@ -49,43 +53,53 @@ class AlbumCard extends HookConsumerWidget { ServiceUtils.navigate(context, "/album/${album.id}", extra: album); }, onPlaybuttonPressed: () async { - if (isPlaylistPlaying && playing) { - return playlistNotifier.pause(); - } else if (isPlaylistPlaying && !playing) { - return playlistNotifier.resume(); - } + updating.value = true; + try { + if (isPlaylistPlaying && playing) { + return playlistNotifier.pause(); + } else if (isPlaylistPlaying && !playing) { + return playlistNotifier.resume(); + } - await playlistNotifier.loadAndPlay(album.tracks - ?.map( - (e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) - .toList() ?? - []); + await playlistNotifier.loadAndPlay(album.tracks + ?.map((e) => + TypeConversionUtils.simpleTrack_X_Track(e, album)) + .toList() ?? + []); + } finally { + updating.value = false; + } }, onAddToQueuePressed: () async { if (isPlaylistPlaying) { return; } - final fetchedTracks = - await queryBowl.fetchQuery, SpotifyApi>( - Queries.album.tracksOf(album.id!), - externalData: ref.read(spotifyProvider), - key: ValueKey(const Uuid().v4()), - ); + updating.value = true; + try { + final fetchedTracks = + await queryBowl.fetchQuery, SpotifyApi>( + Queries.album.tracksOf(album.id!), + externalData: ref.read(spotifyProvider), + key: ValueKey(const Uuid().v4()), + ); - if (fetchedTracks == null || fetchedTracks.isEmpty) return; + if (fetchedTracks == null || fetchedTracks.isEmpty) return; - playlistNotifier.add( - fetchedTracks - .map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) - .toList(), - ); - tracks.value = fetchedTracks; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text("Added ${album.tracks?.length} tracks to queue"), - ), - ); + playlistNotifier.add( + fetchedTracks + .map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) + .toList(), + ); + tracks.value = fetchedTracks; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Added ${album.tracks?.length} tracks to queue"), + ), + ); + } finally { + updating.value = false; + } }); } } diff --git a/lib/components/player/player_controls.dart b/lib/components/player/player_controls.dart index 9fdba0fa7..5c041e5e7 100644 --- a/lib/components/player/player_controls.dart +++ b/lib/components/player/player_controls.dart @@ -38,7 +38,8 @@ class PlayerControls extends HookConsumerWidget { []); final playlist = ref.watch(PlaylistQueueNotifier.provider); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); - final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; + final playing = useStream(PlaylistQueueNotifier.playing).data ?? + PlaylistQueueNotifier.isPlaying; return GestureDetector( behavior: HitTestBehavior.translucent, @@ -89,6 +90,7 @@ class PlayerControls extends HookConsumerWidget { return null; }, [progressStatic]); + // this is a hack to fix duration not being updated useEffect(() { WidgetsBinding.instance.addPostFrameCallback((_) async { if (positionSnapshot.hasData && @@ -200,14 +202,6 @@ class PlayerControls extends HookConsumerWidget { ), onPressed: playlistNotifier.next, ), - PlatformIconButton( - tooltip: "Stop playback", - icon: Icon( - SpotubeIcons.stop, - color: iconColor, - ), - onPressed: playlist != null ? playlistNotifier.stop : null, - ), PlatformIconButton( tooltip: playlist?.isLooping != true ? "Loop Track" diff --git a/lib/components/player/player_overlay.dart b/lib/components/player/player_overlay.dart index c3a9f95e7..07850dfb5 100644 --- a/lib/components/player/player_overlay.dart +++ b/lib/components/player/player_overlay.dart @@ -27,7 +27,8 @@ class PlayerOverlay extends HookConsumerWidget { PlaylistQueueNotifier.provider.select((s) => s != null), ); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); - final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; + final playing = useStream(PlaylistQueueNotifier.playing).data ?? + PlaylistQueueNotifier.isPlaying; return GestureDetector( onVerticalDragEnd: (details) { diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index af57afed6..f36033306 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:platform_ui/platform_ui.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; +import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/track_table/track_tile.dart'; import 'package:spotube/hooks/use_auto_scroll_controller.dart'; @@ -76,7 +77,33 @@ class PlayerQueue extends HookConsumerWidget { borderRadius: BorderRadius.circular(20), ), ), - PlatformText.subheading("Queue"), + PlatformAppBar( + title: + PlatformText.subheading("${tracks.length} tracks in Queue"), + backgroundColor: Colors.transparent, + automaticallyImplyLeading: false, + actions: [ + PlatformFilledButton( + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll( + PlatformTheme.of(context) + .scaffoldBackgroundColor + ?.withOpacity(0.5)), + ), + child: Row( + children: const [ + Icon(SpotubeIcons.playlistRemove), + SizedBox(width: 5), + PlatformText("Clear All"), + ], + ), + onPressed: () { + playlistNotifier.stop(); + Navigator.of(context).pop(); + }, + ), + ], + ), const SizedBox(height: 10), Flexible( child: ListView.builder( diff --git a/lib/components/playlist/playlist_card.dart b/lib/components/playlist/playlist_card.dart index 2f942bd65..acb16fc47 100644 --- a/lib/components/playlist/playlist_card.dart +++ b/lib/components/playlist/playlist_card.dart @@ -24,7 +24,8 @@ class PlaylistCard extends HookConsumerWidget { Widget build(BuildContext context, ref) { final playlistQueue = ref.watch(PlaylistQueueNotifier.provider); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); - final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; + final playing = useStream(PlaylistQueueNotifier.playing).data ?? + PlaylistQueueNotifier.isPlaying; final queryBowl = QueryBowl.of(context); final query = queryBowl.getQuery, SpotifyApi>( Queries.playlist.tracksOf(playlist.id!).queryKey, @@ -34,6 +35,9 @@ class PlaylistCard extends HookConsumerWidget { final int marginH = useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20); + + final updating = useState(false); + return PlaybuttonCard( viewType: viewType, margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()), @@ -43,7 +47,8 @@ class PlaylistCard extends HookConsumerWidget { placeholder: ImagePlaceholder.collection, ), isPlaying: isPlaylistPlaying && playing, - isLoading: isPlaylistPlaying && playlistQueue?.isLoading == true, + isLoading: (isPlaylistPlaying && playlistQueue?.isLoading == true) || + updating.value, onTap: () { ServiceUtils.navigate( context, @@ -52,42 +57,52 @@ class PlaylistCard extends HookConsumerWidget { ); }, onPlaybuttonPressed: () async { - if (isPlaylistPlaying && playing) { - return playlistNotifier.pause(); - } else if (isPlaylistPlaying && !playing) { - return playlistNotifier.resume(); - } + try { + updating.value = true; + if (isPlaylistPlaying && playing) { + return playlistNotifier.pause(); + } else if (isPlaylistPlaying && !playing) { + return playlistNotifier.resume(); + } - List fetchedTracks = await queryBowl.fetchQuery( - key: ValueKey(const Uuid().v4()), - Queries.playlist.tracksOf(playlist.id!), - externalData: ref.read(spotifyProvider), - ) ?? - []; + List fetchedTracks = await queryBowl.fetchQuery( + key: ValueKey(const Uuid().v4()), + Queries.playlist.tracksOf(playlist.id!), + externalData: ref.read(spotifyProvider), + ) ?? + []; - if (fetchedTracks.isEmpty) return; + if (fetchedTracks.isEmpty) return; - await playlistNotifier.loadAndPlay(fetchedTracks); - tracks.value = fetchedTracks; + await playlistNotifier.loadAndPlay(fetchedTracks); + tracks.value = fetchedTracks; + } finally { + updating.value = false; + } }, onAddToQueuePressed: () async { - if (isPlaylistPlaying) return; - List fetchedTracks = await queryBowl.fetchQuery( - key: ValueKey(const Uuid().v4()), - Queries.playlist.tracksOf(playlist.id!), - externalData: ref.read(spotifyProvider), - ) ?? - []; + updating.value = true; + try { + if (isPlaylistPlaying) return; + List fetchedTracks = await queryBowl.fetchQuery( + key: ValueKey(const Uuid().v4()), + Queries.playlist.tracksOf(playlist.id!), + externalData: ref.read(spotifyProvider), + ) ?? + []; - if (fetchedTracks.isEmpty) return; + if (fetchedTracks.isEmpty) return; - playlistNotifier.add(fetchedTracks); - tracks.value = fetchedTracks; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text("Added ${fetchedTracks.length} tracks to queue"), - ), - ); + playlistNotifier.add(fetchedTracks); + tracks.value = fetchedTracks; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Added ${fetchedTracks.length} tracks to queue"), + ), + ); + } finally { + updating.value = false; + } }, ); } diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 0c6dd42f1..31c0f20d0 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -104,7 +104,7 @@ class PlaybuttonCard extends HookWidget { ), ); final addToQueueButton = PlatformIconButton( - onPressed: onAddToQueuePressed, + onPressed: isLoading ? null : onAddToQueuePressed, backgroundColor: PlatformTheme.of(context).secondaryBackgroundColor, hoverColor: PlatformTheme.of(context)