fix: always showing play in playlist/album views

This commit is contained in:
Kingkor Roy Tirtho 2023-08-15 21:57:26 +06:00
parent 4adf6951d9
commit 8521cc5c88
6 changed files with 97 additions and 28 deletions

View File

@ -13,6 +13,12 @@ import 'package:spotube/components/shared/playbutton_card.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
enum PlayButtonState {
playing,
notPlaying,
loading,
}
class TrackCollectionHeading<T> extends HookConsumerWidget {
final String title;
final String? description;
@ -20,7 +26,7 @@ class TrackCollectionHeading<T> extends HookConsumerWidget {
final List<Widget> buttons;
final AlbumSimple? album;
final Query<List<TrackSimple>, T> tracksSnapshot;
final bool isPlaying;
final PlayButtonState playingState;
final void Function([Track? currentTrack]) onPlay;
final void Function([Track? currentTrack]) onShuffledPlay;
final PaletteColor? color;
@ -31,7 +37,7 @@ class TrackCollectionHeading<T> extends HookConsumerWidget {
required this.titleImage,
required this.buttons,
required this.tracksSnapshot,
required this.isPlaying,
required this.playingState,
required this.onPlay,
required this.onShuffledPlay,
required this.color,
@ -155,7 +161,8 @@ class TrackCollectionHeading<T> extends HookConsumerWidget {
label: Text(context.l10n.shuffle),
icon: const Icon(SpotubeIcons.shuffle),
onPressed: tracksSnapshot.data == null ||
isPlaying
playingState ==
PlayButtonState.playing
? null
: onShuffledPlay,
),
@ -167,16 +174,27 @@ class TrackCollectionHeading<T> extends HookConsumerWidget {
backgroundColor: color?.color,
foregroundColor: color?.bodyTextColor,
),
onPressed: tracksSnapshot.data != null
onPressed: tracksSnapshot.data != null ||
playingState ==
PlayButtonState.loading
? onPlay
: null,
icon: Icon(
isPlaying
? SpotubeIcons.stop
: SpotubeIcons.play,
icon: switch (playingState) {
PlayButtonState.playing =>
const Icon(SpotubeIcons.pause),
PlayButtonState.notPlaying =>
const Icon(SpotubeIcons.play),
PlayButtonState.loading =>
const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: .7,
),
),
},
label: Text(
isPlaying
playingState == PlayButtonState.playing
? context.l10n.stop
: context.l10n.play,
),

View File

@ -25,7 +25,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
final String? description;
final Query<List<TrackSimple>, T> tracksSnapshot;
final String titleImage;
final bool isPlaying;
final PlayButtonState playingState;
final void Function([Track? currentTrack]) onPlay;
final void Function([Track? currentTrack]) onShuffledPlay;
final void Function() onAddToQueue;
@ -43,7 +43,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
required this.id,
required this.tracksSnapshot,
required this.titleImage,
required this.isPlaying,
required this.playingState,
required this.onPlay,
required this.onShuffledPlay,
required this.onAddToQueue,
@ -62,6 +62,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final auth = ref.watch(AuthenticationNotifier.provider);
final color = usePaletteGenerator(titleImage).dominantColor;
final List<Widget> buttons = [
@ -72,7 +73,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
),
if (heartBtn != null && auth != null) heartBtn!,
IconButton(
onPressed: isPlaying
onPressed: playingState == PlayButtonState.playing
? null
: tracksSnapshot.data != null
? onAddToQueue
@ -143,7 +144,9 @@ class TrackCollectionView<T> extends HookConsumerWidget {
child: IconButton(
tooltip: context.l10n.shuffle,
icon: const Icon(SpotubeIcons.shuffle),
onPressed: isPlaying ? null : onShuffledPlay,
onPressed: playingState == PlayButtonState.playing
? null
: onShuffledPlay,
),
),
AnimatedScale(
@ -155,8 +158,19 @@ class TrackCollectionView<T> extends HookConsumerWidget {
backgroundColor: theme.colorScheme.inversePrimary,
),
onPressed: tracksSnapshot.data != null ? onPlay : null,
child: Icon(
isPlaying ? SpotubeIcons.stop : SpotubeIcons.play),
child: switch (playingState) {
PlayButtonState.playing =>
const Icon(SpotubeIcons.pause),
PlayButtonState.notPlaying =>
const Icon(SpotubeIcons.play),
PlayButtonState.loading => const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: .7,
),
),
},
),
),
],
@ -185,7 +199,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
title: title,
description: description,
titleImage: titleImage,
isPlaying: isPlaying,
playingState: playingState,
onPlay: onPlay,
onShuffledPlay: onShuffledPlay,
tracksSnapshot: tracksSnapshot,

View File

@ -66,7 +66,7 @@ class SpotubeTrack extends Track {
await client.search("$title - ${artists.join(", ")}").then(
(res) {
final siblings = res
.sorted((a, b) => a.views.compareTo(b.views))
.sorted((a, b) => b.views.compareTo(a.views))
.where((item) {
return artists.any(
(artist) =>

View File

@ -4,9 +4,11 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/shared/heart_button.dart';
import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart';
import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_view.dart';
import 'package:spotube/components/shared/track_table/tracks_table_view.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/service_utils.dart';
@ -26,14 +28,15 @@ class AlbumPage extends HookConsumerWidget {
final sortBy = ref.read(trackCollectionSortState(album.id!));
final sortedTracks = ServiceUtils.sortTracks(tracks, sortBy);
currentTrack ??= sortedTracks.first;
final isPlaylistPlaying = playlist.containsTracks(tracks);
if (!isPlaylistPlaying) {
final isAlbumPlaying = playlist.containsTracks(tracks);
if (!isAlbumPlaying) {
playback.addCollection(album.id!); // for enabling loading indicator
await playback.load(
sortedTracks,
initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id),
);
playback.addCollection(album.id!);
} else if (isPlaylistPlaying &&
} else if (isAlbumPlaying &&
currentTrack.id != null &&
currentTrack.id != playlist.activeTrack?.id) {
await playback.jumpToTrack(currentTrack);
@ -57,12 +60,25 @@ class AlbumPage extends HookConsumerWidget {
final mediaQuery = MediaQuery.of(context);
final isAlbumPlaying = useMemoized(
() => playlist.containsTracks(tracksSnapshot.data ?? []),
[playback, tracksSnapshot.data],
() => playlist.collections.contains(album.id!),
[playlist, album],
);
final albumTrackPlaying = useMemoized(
() =>
tracksSnapshot.data?.any((s) => s.id! == playlist.activeTrack?.id!) ==
true &&
playlist.activeTrack is SpotubeTrack,
[playlist.activeTrack, tracksSnapshot.data],
);
return TrackCollectionView(
id: album.id!,
isPlaying: isAlbumPlaying,
playingState: isAlbumPlaying && albumTrackPlaying
? PlayButtonState.playing
: isAlbumPlaying && !albumTrackPlaying
? PlayButtonState.loading
: PlayButtonState.notPlaying,
title: album.name!,
titleImage: albumArt,
tracksSnapshot: tracksSnapshot,

View File

@ -2,12 +2,14 @@ import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/shared/heart_button.dart';
import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart';
import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_view.dart';
import 'package:spotube/components/shared/track_table/tracks_table_view.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/models/logger.dart';
import 'package:flutter/material.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/queries/queries.dart';
@ -31,6 +33,7 @@ class PlaylistView extends HookConsumerWidget {
currentTrack ??= sortedTracks.first;
final isPlaylistPlaying = proxyPlaylist.containsTracks(tracks);
if (!isPlaylistPlaying) {
playback.addCollection(playlist.id!); // for enabling loading indicator
await playback.load(
sortedTracks,
initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id),
@ -55,8 +58,8 @@ class PlaylistView extends HookConsumerWidget {
final tracksSnapshot = useQueries.playlist.tracksOfQuery(ref, playlist.id!);
final isPlaylistPlaying = useMemoized(
() => proxyPlaylist.containsTracks(tracksSnapshot.data ?? []),
[playlistNotifier, tracksSnapshot.data],
() => proxyPlaylist.collections.contains(playlist.id!),
[proxyPlaylist, playlist],
);
final titleImage = useMemoized(
@ -66,9 +69,22 @@ class PlaylistView extends HookConsumerWidget {
),
[playlist.images]);
final playlistTrackPlaying = useMemoized(
() =>
tracksSnapshot.data
?.any((s) => s.id! == proxyPlaylist.activeTrack?.id!) ==
true &&
proxyPlaylist.activeTrack is SpotubeTrack,
[proxyPlaylist.activeTrack, tracksSnapshot.data],
);
return TrackCollectionView(
id: playlist.id!,
isPlaying: isPlaylistPlaying,
playingState: isPlaylistPlaying && playlistTrackPlaying
? PlayButtonState.playing
: isPlaylistPlaying && !playlistTrackPlaying
? PlayButtonState.loading
: PlayButtonState.notPlaying,
title: playlist.name!,
titleImage: titleImage,
tracksSnapshot: tracksSnapshot,

View File

@ -290,7 +290,12 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist>
final addableTrack = await SpotubeTrack.fetchFromTrack(
tracks.elementAtOrNull(initialIndex) ?? tracks.first,
youtube,
).catchError((e, stackTrace) {
return SpotubeTrack.fetchFromTrack(
tracks.elementAtOrNull(initialIndex + 1) ?? tracks.first,
youtube,
);
});
state = state.copyWith(
tracks: mergeTracks([addableTrack], tracks),