mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
fix: always showing play in playlist/album views
This commit is contained in:
parent
4adf6951d9
commit
8521cc5c88
@ -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,
|
||||
),
|
||||
|
@ -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,
|
||||
|
@ -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) =>
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user