refactor: use provider based is track loading implementation

This commit is contained in:
Kingkor Roy Tirtho 2024-06-24 21:01:09 +06:00
parent a83dd64476
commit 75173e5096
9 changed files with 216 additions and 207 deletions

View File

@ -11,7 +11,7 @@ import 'package:spotube/pages/home/home.dart';
import 'package:spotube/pages/library/library.dart'; import 'package:spotube/pages/library/library.dart';
import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/lyrics/lyrics.dart';
import 'package:spotube/pages/search/search.dart'; import 'package:spotube/pages/search/search.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/platform.dart';
@ -96,8 +96,8 @@ class SeekIntent extends Intent {
class SeekAction extends Action<SeekIntent> { class SeekAction extends Action<SeekIntent> {
@override @override
invoke(intent) async { invoke(intent) async {
final playlist = intent.ref.read(audioPlayerProvider.notifier); final isFetchingActiveTrack = intent.ref.read(queryingTrackInfoProvider);
if (playlist.isFetching()) { if (isFetchingActiveTrack) {
DirectionalFocusAction().invoke( DirectionalFocusAction().invoke(
DirectionalFocusIntent( DirectionalFocusIntent(
intent.forward ? TraversalDirection.right : TraversalDirection.left, intent.forward ? TraversalDirection.right : TraversalDirection.left,

View File

@ -17,7 +17,7 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/duration.dart';
import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/image.dart';
import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/local_track.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/audio_player/state.dart';
import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart';
@ -84,8 +84,7 @@ class TrackTile extends HookConsumerWidget {
}, },
child: HoverBuilder( child: HoverBuilder(
permanentState: isSelected || constrains.smAndDown ? true : null, permanentState: isSelected || constrains.smAndDown ? true : null,
builder: (context, isHovering) { builder: (context, isHovering) => ListTile(
return ListTile(
selected: isSelected, selected: isSelected,
onTap: () async { onTap: () async {
try { try {
@ -100,8 +99,7 @@ class TrackTile extends HookConsumerWidget {
onLongPress: onLongPress, onLongPress: onLongPress,
enabled: !isBlackListed, enabled: !isBlackListed,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
tileColor: tileColor: isBlackListed ? theme.colorScheme.errorContainer : null,
isBlackListed ? theme.colorScheme.errorContainer : null,
horizontalTitleGap: 12, horizontalTitleGap: 12,
leadingAndTrailingTextStyle: theme.textTheme.bodyMedium, leadingAndTrailingTextStyle: theme.textTheme.bodyMedium,
leading: Row( leading: Row(
@ -159,13 +157,13 @@ class TrackTile extends HookConsumerWidget {
data: theme.iconTheme data: theme.iconTheme
.copyWith(size: 26, color: Colors.white), .copyWith(size: 26, color: Colors.white),
child: Skeleton.ignore( child: Skeleton.ignore(
child: AnimatedSwitcher( child: Consumer(
builder: (context, ref, _) {
final isFetchingActiveTrack =
ref.watch(queryingTrackInfoProvider);
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: (isPlaying && child: (isPlaying && isFetchingActiveTrack) ||
ref
.watch(audioPlayerProvider
.notifier)
.isFetching()) ||
isLoading.value isLoading.value
? const SizedBox( ? const SizedBox(
width: 26, width: 26,
@ -183,6 +181,8 @@ class TrackTile extends HookConsumerWidget {
: !isHovering : !isHovering
? const SizedBox.shrink() ? const SizedBox.shrink()
: const Icon(SpotubeIcons.play), : const Icon(SpotubeIcons.play),
);
},
), ),
), ),
), ),
@ -267,8 +267,7 @@ class TrackTile extends HookConsumerWidget {
), ),
], ],
), ),
); ),
},
), ),
); );
}); });

View File

@ -10,6 +10,7 @@ import 'package:spotube/extensions/image.dart';
import 'package:spotube/extensions/track.dart'; import 'package:spotube/extensions/track.dart';
import 'package:spotube/models/connect/connect.dart'; import 'package:spotube/models/connect/connect.dart';
import 'package:spotube/pages/album/album.dart'; import 'package:spotube/pages/album/album.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/connect/connect.dart';
import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/history/history.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
@ -35,6 +36,7 @@ class AlbumCard extends HookConsumerWidget {
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final playlistNotifier = ref.watch(audioPlayerProvider.notifier);
final historyNotifier = ref.read(playbackHistoryProvider.notifier); final historyNotifier = ref.read(playbackHistoryProvider.notifier);
final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
bool isPlaylistPlaying = useMemoized( bool isPlaylistPlaying = useMemoized(
() => playlist.containsCollection(album.id!), () => playlist.containsCollection(album.id!),
@ -59,8 +61,8 @@ class AlbumCard extends HookConsumerWidget {
), ),
margin: const EdgeInsets.symmetric(horizontal: 10), margin: const EdgeInsets.symmetric(horizontal: 10),
isPlaying: isPlaylistPlaying, isPlaying: isPlaylistPlaying,
isLoading: (isPlaylistPlaying && playlistNotifier.isFetching()) || isLoading:
updating.value, (isPlaylistPlaying && isFetchingActiveTrack) || updating.value,
title: album.name!, title: album.name!,
description: description:
"${album.albumType?.formatted}${album.artists?.asString() ?? ""}", "${album.albumType?.formatted}${album.artists?.asString() ?? ""}",

View File

@ -11,7 +11,7 @@ import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/duration.dart';
import 'package:spotube/modules/player/use_progress.dart'; import 'package:spotube/modules/player/use_progress.dart';
import 'package:spotube/models/logger.dart'; import 'package:spotube/models/logger.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
class PlayerControls extends HookConsumerWidget { class PlayerControls extends HookConsumerWidget {
@ -43,8 +43,7 @@ class PlayerControls extends HookConsumerWidget {
SeekIntent: SeekAction(), SeekIntent: SeekAction(),
}, },
[]); []);
ref.watch(audioPlayerProvider); final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
final playlistNotifier = ref.watch(audioPlayerProvider.notifier);
final playing = final playing =
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
@ -132,7 +131,7 @@ class PlayerControls extends HookConsumerWidget {
// than total duration. Keeping it resolved // than total duration. Keeping it resolved
value: progress.value.toDouble(), value: progress.value.toDouble(),
secondaryTrackValue: bufferProgress, secondaryTrackValue: bufferProgress,
onChanged: playlistNotifier.isFetching() onChanged: isFetchingActiveTrack
? null ? null
: (v) { : (v) {
progress.value = v; progress.value = v;
@ -183,7 +182,7 @@ class PlayerControls extends HookConsumerWidget {
: context.l10n.shuffle_playlist, : context.l10n.shuffle_playlist,
icon: const Icon(SpotubeIcons.shuffle), icon: const Icon(SpotubeIcons.shuffle),
style: shuffled ? activeButtonStyle : buttonStyle, style: shuffled ? activeButtonStyle : buttonStyle,
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: () { : () {
if (shuffled) { if (shuffled) {
@ -198,7 +197,7 @@ class PlayerControls extends HookConsumerWidget {
tooltip: context.l10n.previous_track, tooltip: context.l10n.previous_track,
icon: const Icon(SpotubeIcons.skipBack), icon: const Icon(SpotubeIcons.skipBack),
style: buttonStyle, style: buttonStyle,
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: audioPlayer.skipToPrevious, : audioPlayer.skipToPrevious,
), ),
@ -206,7 +205,7 @@ class PlayerControls extends HookConsumerWidget {
tooltip: playing tooltip: playing
? context.l10n.pause_playback ? context.l10n.pause_playback
: context.l10n.resume_playback, : context.l10n.resume_playback,
icon: playlistNotifier.isFetching() icon: isFetchingActiveTrack
? SizedBox( ? SizedBox(
height: 20, height: 20,
width: 20, width: 20,
@ -219,7 +218,7 @@ class PlayerControls extends HookConsumerWidget {
playing ? SpotubeIcons.pause : SpotubeIcons.play, playing ? SpotubeIcons.pause : SpotubeIcons.play,
), ),
style: resumePauseStyle, style: resumePauseStyle,
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: Actions.handler<PlayPauseIntent>( : Actions.handler<PlayPauseIntent>(
context, context,
@ -230,9 +229,8 @@ class PlayerControls extends HookConsumerWidget {
tooltip: context.l10n.next_track, tooltip: context.l10n.next_track,
icon: const Icon(SpotubeIcons.skipForward), icon: const Icon(SpotubeIcons.skipForward),
style: buttonStyle, style: buttonStyle,
onPressed: playlistNotifier.isFetching() onPressed:
? null isFetchingActiveTrack ? null : audioPlayer.skipToNext,
: audioPlayer.skipToNext,
), ),
StreamBuilder<PlaylistMode>( StreamBuilder<PlaylistMode>(
stream: audioPlayer.loopModeStream, stream: audioPlayer.loopModeStream,
@ -253,7 +251,7 @@ class PlayerControls extends HookConsumerWidget {
loopMode == PlaylistMode.loop loopMode == PlaylistMode.loop
? activeButtonStyle ? activeButtonStyle
: buttonStyle, : buttonStyle,
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: () async { : () async {
await audioPlayer.setLoopMode(loopMode); await audioPlayer.setLoopMode(loopMode);

View File

@ -12,6 +12,7 @@ import 'package:spotube/collections/intents.dart';
import 'package:spotube/modules/player/use_progress.dart'; import 'package:spotube/modules/player/use_progress.dart';
import 'package:spotube/modules/player/player.dart'; import 'package:spotube/modules/player/player.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
class PlayerOverlay extends HookConsumerWidget { class PlayerOverlay extends HookConsumerWidget {
@ -24,7 +25,7 @@ class PlayerOverlay extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
final playlist = ref.watch(audioPlayerProvider); final playlist = ref.watch(audioPlayerProvider);
final canShow = playlist.activeTrack != null; final canShow = playlist.activeTrack != null;
@ -127,14 +128,14 @@ class PlayerOverlay extends HookConsumerWidget {
SpotubeIcons.skipBack, SpotubeIcons.skipBack,
color: textColor, color: textColor,
), ),
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: audioPlayer.skipToPrevious, : audioPlayer.skipToPrevious,
), ),
Consumer( Consumer(
builder: (context, ref, _) { builder: (context, ref, _) {
return IconButton( return IconButton(
icon: playlistNotifier.isFetching() icon: isFetchingActiveTrack
? const SizedBox( ? const SizedBox(
height: 20, height: 20,
width: 20, width: 20,
@ -158,7 +159,7 @@ class PlayerOverlay extends HookConsumerWidget {
SpotubeIcons.skipForward, SpotubeIcons.skipForward,
color: textColor, color: textColor,
), ),
onPressed: playlistNotifier.isFetching() onPressed: isFetchingActiveTrack
? null ? null
: audioPlayer.skipToNext, : audioPlayer.skipToNext,
), ),

View File

@ -16,6 +16,7 @@ import 'package:spotube/extensions/duration.dart';
import 'package:spotube/hooks/utils/use_debounce.dart'; import 'package:spotube/hooks/utils/use_debounce.dart';
import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/database/database.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/provider/server/active_sourced_track.dart'; import 'package:spotube/provider/server/active_sourced_track.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
@ -54,7 +55,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context); final theme = Theme.of(context);
final playlist = ref.watch(audioPlayerProvider); final playlist = ref.watch(audioPlayerProvider);
final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
final preferences = ref.watch(userPreferencesProvider); final preferences = ref.watch(userPreferencesProvider);
final isSearching = useState(false); final isSearching = useState(false);
@ -130,7 +131,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
]); ]);
final siblings = useMemoized( final siblings = useMemoized(
() => playlistNotifier.isFetching() () => isFetchingActiveTrack
? [ ? [
(activeTrack as SourcedTrack).sourceInfo, (activeTrack as SourcedTrack).sourceInfo,
...activeTrack.siblings, ...activeTrack.siblings,
@ -176,12 +177,12 @@ class SiblingTracksSheet extends HookConsumerWidget {
Text("${sourceInfo.artist}"), Text("${sourceInfo.artist}"),
], ],
), ),
enabled: !playlistNotifier.isFetching(), enabled: !isFetchingActiveTrack,
selected: !playlistNotifier.isFetching() && selected: !isFetchingActiveTrack &&
sourceInfo.id == (activeTrack as SourcedTrack).sourceInfo.id, sourceInfo.id == (activeTrack as SourcedTrack).sourceInfo.id,
selectedTileColor: theme.popupMenuTheme.color, selectedTileColor: theme.popupMenuTheme.color,
onTap: () { onTap: () {
if (!playlistNotifier.isFetching() && if (!isFetchingActiveTrack &&
sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) { sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) {
activeTrackNotifier.swapSibling(sourceInfo); activeTrackNotifier.swapSibling(sourceInfo);
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@ -7,6 +7,7 @@ import 'package:spotube/components/playbutton_card.dart';
import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/image.dart';
import 'package:spotube/models/connect/connect.dart'; import 'package:spotube/models/connect/connect.dart';
import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/pages/playlist/playlist.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/connect/connect.dart';
import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/history/history.dart';
import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart';
@ -24,6 +25,7 @@ class PlaylistCard extends HookConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final playlistQueue = ref.watch(audioPlayerProvider); final playlistQueue = ref.watch(audioPlayerProvider);
final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final playlistNotifier = ref.watch(audioPlayerProvider.notifier);
final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
final historyNotifier = ref.read(playbackHistoryProvider.notifier); final historyNotifier = ref.read(playbackHistoryProvider.notifier);
final playing = final playing =
@ -65,8 +67,7 @@ class PlaylistCard extends HookConsumerWidget {
placeholder: ImagePlaceholder.collection, placeholder: ImagePlaceholder.collection,
), ),
isPlaying: isPlaylistPlaying, isPlaying: isPlaylistPlaying,
isLoading: (isPlaylistPlaying && playlistNotifier.isFetching()) || isLoading: (isPlaylistPlaying && isFetchingActiveTrack) || updating.value,
updating.value,
isOwner: playlist.owner?.id == me.asData?.value.id && isOwner: playlist.owner?.id == me.asData?.value.id &&
me.asData?.value.id != null, me.asData?.value.id != null,
onTap: () { onTap: () {

View File

@ -299,11 +299,6 @@ class AudioPlayerNotifier extends Notifier<AudioPlayerState> {
await audioPlayer.moveTrack(oldIndex, newIndex); await audioPlayer.moveTrack(oldIndex, newIndex);
} }
bool isFetching() {
if (state.activeTrack == null) return false;
return ref.read(sourcedTrackProvider(state.activeTrack!)).isLoading;
}
Future<void> stop() async { Future<void> stop() async {
await audioPlayer.stop(); await audioPlayer.stop();
ref.read(discordProvider.notifier).clear(); ref.read(discordProvider.notifier).clear();

View File

@ -0,0 +1,12 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/server/sourced_track.dart';
final queryingTrackInfoProvider = Provider<bool>((ref) {
final activeTrack =
ref.watch(audioPlayerProvider.select((s) => s.activeTrack));
if (activeTrack == null) return false;
return ref.read(sourcedTrackProvider(activeTrack)).isLoading;
});