Skip to content

Commit

Permalink
fix: always showing play in playlist/album views
Browse files Browse the repository at this point in the history
  • Loading branch information
KRTirtho committed Aug 15, 2023
1 parent 4adf695 commit 8521cc5
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ 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;
final String titleImage;
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;
Expand All @@ -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,
Expand Down Expand Up @@ -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,
),
Expand All @@ -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,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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 = [
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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,
),
),
},
),
),
],
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion lib/models/spotube_track.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
28 changes: 22 additions & 6 deletions lib/pages/album/album.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);
Expand All @@ -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,
Expand Down
22 changes: 19 additions & 3 deletions lib/pages/playlist/playlist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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),
Expand All @@ -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(
Expand All @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion lib/provider/proxy_playlist/proxy_playlist_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down

0 comments on commit 8521cc5

Please sign in to comment.