mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
refactor: use provider based is track loading implementation
This commit is contained in:
parent
a83dd64476
commit
75173e5096
@ -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,
|
||||||
|
@ -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,191 +84,190 @@ 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 {
|
isLoading.value = true;
|
||||||
isLoading.value = true;
|
await onTap?.call();
|
||||||
await onTap?.call();
|
} finally {
|
||||||
} finally {
|
if (context.mounted) {
|
||||||
if (context.mounted) {
|
isLoading.value = false;
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
onLongPress: onLongPress,
|
},
|
||||||
enabled: !isBlackListed,
|
onLongPress: onLongPress,
|
||||||
contentPadding: EdgeInsets.zero,
|
enabled: !isBlackListed,
|
||||||
tileColor:
|
contentPadding: EdgeInsets.zero,
|
||||||
isBlackListed ? theme.colorScheme.errorContainer : null,
|
tileColor: isBlackListed ? theme.colorScheme.errorContainer : null,
|
||||||
horizontalTitleGap: 12,
|
horizontalTitleGap: 12,
|
||||||
leadingAndTrailingTextStyle: theme.textTheme.bodyMedium,
|
leadingAndTrailingTextStyle: theme.textTheme.bodyMedium,
|
||||||
leading: Row(
|
leading: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
...?leadingActions,
|
...?leadingActions,
|
||||||
if (index != null && onChanged == null && constrains.mdAndUp)
|
if (index != null && onChanged == null && constrains.mdAndUp)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 50,
|
width: 50,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${(index ?? 0) + 1}',
|
'${(index ?? 0) + 1}',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: theme.textTheme.bodySmall,
|
style: theme.textTheme.bodySmall,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
|
||||||
else if (constrains.smAndDown)
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
if (onChanged != null)
|
|
||||||
Checkbox(
|
|
||||||
value: selected,
|
|
||||||
onChanged: onChanged,
|
|
||||||
),
|
),
|
||||||
Stack(
|
)
|
||||||
children: [
|
else if (constrains.smAndDown)
|
||||||
ClipRRect(
|
const SizedBox(width: 16),
|
||||||
borderRadius: BorderRadius.circular(4),
|
if (onChanged != null)
|
||||||
child: AspectRatio(
|
Checkbox(
|
||||||
aspectRatio: 1,
|
value: selected,
|
||||||
child: UniversalImage(
|
onChanged: onChanged,
|
||||||
path: (track.album?.images).asUrlString(
|
|
||||||
placeholder: ImagePlaceholder.albumArt,
|
|
||||||
),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: isHovering
|
|
||||||
? Colors.black.withOpacity(0.4)
|
|
||||||
: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: Center(
|
|
||||||
child: IconTheme(
|
|
||||||
data: theme.iconTheme
|
|
||||||
.copyWith(size: 26, color: Colors.white),
|
|
||||||
child: Skeleton.ignore(
|
|
||||||
child: AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
child: (isPlaying &&
|
|
||||||
ref
|
|
||||||
.watch(audioPlayerProvider
|
|
||||||
.notifier)
|
|
||||||
.isFetching()) ||
|
|
||||||
isLoading.value
|
|
||||||
? const SizedBox(
|
|
||||||
width: 26,
|
|
||||||
height: 26,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 1.5,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: isPlaying
|
|
||||||
? Icon(
|
|
||||||
SpotubeIcons.pause,
|
|
||||||
color: theme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
: !isHovering
|
|
||||||
? const SizedBox.shrink()
|
|
||||||
: const Icon(SpotubeIcons.play),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
Stack(
|
||||||
),
|
children: [
|
||||||
title: Row(
|
ClipRRect(
|
||||||
children: [
|
borderRadius: BorderRadius.circular(4),
|
||||||
Expanded(
|
child: AspectRatio(
|
||||||
flex: 6,
|
aspectRatio: 1,
|
||||||
child: switch (track) {
|
child: UniversalImage(
|
||||||
LocalTrack() => Text(
|
path: (track.album?.images).asUrlString(
|
||||||
track.name!,
|
placeholder: ImagePlaceholder.albumArt,
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
_ => LinkText(
|
|
||||||
track.name!,
|
|
||||||
"/track/${track.id}",
|
|
||||||
push: true,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (constrains.mdAndUp) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
flex: 4,
|
|
||||||
child: switch (track) {
|
|
||||||
LocalTrack() => Text(
|
|
||||||
track.album!.name!,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
_ => Align(
|
fit: BoxFit.cover,
|
||||||
alignment: Alignment.centerLeft,
|
),
|
||||||
child: LinkText(
|
),
|
||||||
track.album!.name!,
|
),
|
||||||
"/album/${track.album?.id}",
|
Positioned.fill(
|
||||||
extra: track.album,
|
child: AnimatedContainer(
|
||||||
push: true,
|
duration: const Duration(milliseconds: 300),
|
||||||
overflow: TextOverflow.ellipsis,
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
color: isHovering
|
||||||
|
? Colors.black.withOpacity(0.4)
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: Center(
|
||||||
|
child: IconTheme(
|
||||||
|
data: theme.iconTheme
|
||||||
|
.copyWith(size: 26, color: Colors.white),
|
||||||
|
child: Skeleton.ignore(
|
||||||
|
child: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final isFetchingActiveTrack =
|
||||||
|
ref.watch(queryingTrackInfoProvider);
|
||||||
|
return AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: (isPlaying && isFetchingActiveTrack) ||
|
||||||
|
isLoading.value
|
||||||
|
? const SizedBox(
|
||||||
|
width: 26,
|
||||||
|
height: 26,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: isPlaying
|
||||||
|
? Icon(
|
||||||
|
SpotubeIcons.pause,
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
: !isHovering
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: const Icon(SpotubeIcons.play),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
},
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
subtitle: Align(
|
),
|
||||||
alignment: Alignment.centerLeft,
|
title: Row(
|
||||||
child: track is LocalTrack
|
children: [
|
||||||
? Text(
|
Expanded(
|
||||||
track.artists?.asString() ?? '',
|
flex: 6,
|
||||||
)
|
child: switch (track) {
|
||||||
: ClipRect(
|
LocalTrack() => Text(
|
||||||
child: ConstrainedBox(
|
track.name!,
|
||||||
constraints: const BoxConstraints(maxHeight: 40),
|
maxLines: 1,
|
||||||
child: ArtistLink(artists: track.artists ?? []),
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
_ => LinkText(
|
||||||
trailing: Row(
|
track.name!,
|
||||||
mainAxisSize: MainAxisSize.min,
|
"/track/${track.id}",
|
||||||
children: [
|
push: true,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (constrains.mdAndUp) ...[
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Expanded(
|
||||||
Duration(milliseconds: track.durationMs ?? 0)
|
flex: 4,
|
||||||
.toHumanReadableString(padZero: false),
|
child: switch (track) {
|
||||||
maxLines: 1,
|
LocalTrack() => Text(
|
||||||
overflow: TextOverflow.ellipsis,
|
track.album!.name!,
|
||||||
),
|
maxLines: 1,
|
||||||
TrackOptions(
|
overflow: TextOverflow.ellipsis,
|
||||||
track: track,
|
),
|
||||||
playlistId: playlistId,
|
_ => Align(
|
||||||
userPlaylist: userPlaylist,
|
alignment: Alignment.centerLeft,
|
||||||
showMenuCbRef: showOptionCbRef,
|
child: LinkText(
|
||||||
|
track.album!.name!,
|
||||||
|
"/album/${track.album?.id}",
|
||||||
|
extra: track.album,
|
||||||
|
push: true,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
],
|
||||||
);
|
),
|
||||||
},
|
subtitle: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: track is LocalTrack
|
||||||
|
? Text(
|
||||||
|
track.artists?.asString() ?? '',
|
||||||
|
)
|
||||||
|
: ClipRect(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 40),
|
||||||
|
child: ArtistLink(artists: track.artists ?? []),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
Duration(milliseconds: track.durationMs ?? 0)
|
||||||
|
.toHumanReadableString(padZero: false),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
TrackOptions(
|
||||||
|
track: track,
|
||||||
|
playlistId: playlistId,
|
||||||
|
userPlaylist: userPlaylist,
|
||||||
|
showMenuCbRef: showOptionCbRef,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -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() ?? ""}",
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -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();
|
||||||
|
@ -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: () {
|
||||||
|
@ -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();
|
||||||
|
12
lib/provider/audio_player/querying_track_info.dart
Normal file
12
lib/provider/audio_player/querying_track_info.dart
Normal 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;
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user