fix: playbutton card play state not changing

refactor(player_controls): move stop playback button to queue sheet
This commit is contained in:
Kingkor Roy Tirtho 2023-02-05 20:47:42 +06:00
parent b8f3493138
commit ee46d0970b
6 changed files with 125 additions and 74 deletions

View File

@ -24,7 +24,8 @@ class AlbumCard extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final playlist = ref.watch(PlaylistQueueNotifier.provider); 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 playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final queryBowl = QueryBowl.of(context); final queryBowl = QueryBowl.of(context);
final query = queryBowl.getQuery<List<TrackSimple>, SpotifyApi>( final query = queryBowl.getQuery<List<TrackSimple>, SpotifyApi>(
@ -33,6 +34,9 @@ class AlbumCard extends HookConsumerWidget {
bool isPlaylistPlaying = playlistNotifier.isPlayingPlaylist(tracks.value); bool isPlaylistPlaying = playlistNotifier.isPlayingPlaylist(tracks.value);
final int marginH = final int marginH =
useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20); useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20);
final updating = useState(false);
return PlaybuttonCard( return PlaybuttonCard(
imageUrl: TypeConversionUtils.image_X_UrlString( imageUrl: TypeConversionUtils.image_X_UrlString(
album.images, album.images,
@ -49,43 +53,53 @@ class AlbumCard extends HookConsumerWidget {
ServiceUtils.navigate(context, "/album/${album.id}", extra: album); ServiceUtils.navigate(context, "/album/${album.id}", extra: album);
}, },
onPlaybuttonPressed: () async { onPlaybuttonPressed: () async {
if (isPlaylistPlaying && playing) { updating.value = true;
return playlistNotifier.pause(); try {
} else if (isPlaylistPlaying && !playing) { if (isPlaylistPlaying && playing) {
return playlistNotifier.resume(); return playlistNotifier.pause();
} } else if (isPlaylistPlaying && !playing) {
return playlistNotifier.resume();
}
await playlistNotifier.loadAndPlay(album.tracks await playlistNotifier.loadAndPlay(album.tracks
?.map( ?.map((e) =>
(e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) TypeConversionUtils.simpleTrack_X_Track(e, album))
.toList() ?? .toList() ??
[]); []);
} finally {
updating.value = false;
}
}, },
onAddToQueuePressed: () async { onAddToQueuePressed: () async {
if (isPlaylistPlaying) { if (isPlaylistPlaying) {
return; return;
} }
final fetchedTracks = updating.value = true;
await queryBowl.fetchQuery<List<TrackSimple>, SpotifyApi>( try {
Queries.album.tracksOf(album.id!), final fetchedTracks =
externalData: ref.read(spotifyProvider), await queryBowl.fetchQuery<List<TrackSimple>, SpotifyApi>(
key: ValueKey(const Uuid().v4()), 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( playlistNotifier.add(
fetchedTracks fetchedTracks
.map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) .map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album))
.toList(), .toList(),
); );
tracks.value = fetchedTracks; tracks.value = fetchedTracks;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text("Added ${album.tracks?.length} tracks to queue"), content: Text("Added ${album.tracks?.length} tracks to queue"),
), ),
); );
} finally {
updating.value = false;
}
}); });
} }
} }

View File

@ -38,7 +38,8 @@ class PlayerControls extends HookConsumerWidget {
[]); []);
final playlist = ref.watch(PlaylistQueueNotifier.provider); final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
@ -89,6 +90,7 @@ class PlayerControls extends HookConsumerWidget {
return null; return null;
}, [progressStatic]); }, [progressStatic]);
// this is a hack to fix duration not being updated
useEffect(() { useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (positionSnapshot.hasData && if (positionSnapshot.hasData &&
@ -200,14 +202,6 @@ class PlayerControls extends HookConsumerWidget {
), ),
onPressed: playlistNotifier.next, onPressed: playlistNotifier.next,
), ),
PlatformIconButton(
tooltip: "Stop playback",
icon: Icon(
SpotubeIcons.stop,
color: iconColor,
),
onPressed: playlist != null ? playlistNotifier.stop : null,
),
PlatformIconButton( PlatformIconButton(
tooltip: playlist?.isLooping != true tooltip: playlist?.isLooping != true
? "Loop Track" ? "Loop Track"

View File

@ -27,7 +27,8 @@ class PlayerOverlay extends HookConsumerWidget {
PlaylistQueueNotifier.provider.select((s) => s != null), PlaylistQueueNotifier.provider.select((s) => s != null),
); );
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playing = useStream(PlaylistQueueNotifier.playing).data ?? false; final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying;
return GestureDetector( return GestureDetector(
onVerticalDragEnd: (details) { onVerticalDragEnd: (details) {

View File

@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:platform_ui/platform_ui.dart'; import 'package:platform_ui/platform_ui.dart';
import 'package:scroll_to_index/scroll_to_index.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/fallbacks/not_found.dart';
import 'package:spotube/components/shared/track_table/track_tile.dart'; import 'package:spotube/components/shared/track_table/track_tile.dart';
import 'package:spotube/hooks/use_auto_scroll_controller.dart'; import 'package:spotube/hooks/use_auto_scroll_controller.dart';
@ -76,7 +77,33 @@ class PlayerQueue extends HookConsumerWidget {
borderRadius: BorderRadius.circular(20), 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), const SizedBox(height: 10),
Flexible( Flexible(
child: ListView.builder( child: ListView.builder(

View File

@ -24,7 +24,8 @@ class PlaylistCard extends HookConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final playlistQueue = ref.watch(PlaylistQueueNotifier.provider); final playlistQueue = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); 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 queryBowl = QueryBowl.of(context);
final query = queryBowl.getQuery<List<Track>, SpotifyApi>( final query = queryBowl.getQuery<List<Track>, SpotifyApi>(
Queries.playlist.tracksOf(playlist.id!).queryKey, Queries.playlist.tracksOf(playlist.id!).queryKey,
@ -34,6 +35,9 @@ class PlaylistCard extends HookConsumerWidget {
final int marginH = final int marginH =
useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20); useBreakpointValue(sm: 10, md: 15, lg: 20, xl: 20, xxl: 20);
final updating = useState(false);
return PlaybuttonCard( return PlaybuttonCard(
viewType: viewType, viewType: viewType,
margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()), margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()),
@ -43,7 +47,8 @@ class PlaylistCard extends HookConsumerWidget {
placeholder: ImagePlaceholder.collection, placeholder: ImagePlaceholder.collection,
), ),
isPlaying: isPlaylistPlaying && playing, isPlaying: isPlaylistPlaying && playing,
isLoading: isPlaylistPlaying && playlistQueue?.isLoading == true, isLoading: (isPlaylistPlaying && playlistQueue?.isLoading == true) ||
updating.value,
onTap: () { onTap: () {
ServiceUtils.navigate( ServiceUtils.navigate(
context, context,
@ -52,42 +57,52 @@ class PlaylistCard extends HookConsumerWidget {
); );
}, },
onPlaybuttonPressed: () async { onPlaybuttonPressed: () async {
if (isPlaylistPlaying && playing) { try {
return playlistNotifier.pause(); updating.value = true;
} else if (isPlaylistPlaying && !playing) { if (isPlaylistPlaying && playing) {
return playlistNotifier.resume(); return playlistNotifier.pause();
} else if (isPlaylistPlaying && !playing) {
return playlistNotifier.resume();
}
List<Track> fetchedTracks = await queryBowl.fetchQuery(
key: ValueKey(const Uuid().v4()),
Queries.playlist.tracksOf(playlist.id!),
externalData: ref.read(spotifyProvider),
) ??
[];
if (fetchedTracks.isEmpty) return;
await playlistNotifier.loadAndPlay(fetchedTracks);
tracks.value = fetchedTracks;
} finally {
updating.value = false;
} }
List<Track> fetchedTracks = await queryBowl.fetchQuery(
key: ValueKey(const Uuid().v4()),
Queries.playlist.tracksOf(playlist.id!),
externalData: ref.read(spotifyProvider),
) ??
[];
if (fetchedTracks.isEmpty) return;
await playlistNotifier.loadAndPlay(fetchedTracks);
tracks.value = fetchedTracks;
}, },
onAddToQueuePressed: () async { onAddToQueuePressed: () async {
if (isPlaylistPlaying) return; updating.value = true;
List<Track> fetchedTracks = await queryBowl.fetchQuery( try {
key: ValueKey(const Uuid().v4()), if (isPlaylistPlaying) return;
Queries.playlist.tracksOf(playlist.id!), List<Track> fetchedTracks = await queryBowl.fetchQuery(
externalData: ref.read(spotifyProvider), 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); playlistNotifier.add(fetchedTracks);
tracks.value = fetchedTracks; tracks.value = fetchedTracks;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text("Added ${fetchedTracks.length} tracks to queue"), content: Text("Added ${fetchedTracks.length} tracks to queue"),
), ),
); );
} finally {
updating.value = false;
}
}, },
); );
} }

View File

@ -104,7 +104,7 @@ class PlaybuttonCard extends HookWidget {
), ),
); );
final addToQueueButton = PlatformIconButton( final addToQueueButton = PlatformIconButton(
onPressed: onAddToQueuePressed, onPressed: isLoading ? null : onAddToQueuePressed,
backgroundColor: backgroundColor:
PlatformTheme.of(context).secondaryBackgroundColor, PlatformTheme.of(context).secondaryBackgroundColor,
hoverColor: PlatformTheme.of(context) hoverColor: PlatformTheme.of(context)