chore: fix queue order

This commit is contained in:
Kingkor Roy Tirtho 2025-07-19 21:39:31 +06:00
parent cfda46e07e
commit 0a604a9ad5
4 changed files with 88 additions and 54 deletions

View File

@ -15,10 +15,11 @@ import 'package:spotube/provider/history/history.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
class TrackPresentationActionsSection extends HookConsumerWidget {
const TrackPresentationActionsSection({super.key});
showToastForAction(BuildContext context, String action, int count) {
ToastOverlay showToastForAction(
BuildContext context,
String action,
int count,
) {
final message = switch (action) {
"download" => (context.l10n.download_count(count), SpotubeIcons.download),
"add-to-playlist" => (
@ -36,7 +37,7 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
_ => ("", SpotubeIcons.error),
};
showToast(
return showToast(
context: context,
location: ToastLocation.topRight,
builder: (context, overlay) {
@ -56,7 +57,10 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
);
},
);
}
}
class TrackPresentationActionsSection extends HookConsumerWidget {
const TrackPresentationActionsSection({super.key});
@override
Widget build(BuildContext context, ref) {

View File

@ -30,7 +30,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
final imageDimension = mediaQuery.mdAndUp ? 200 : 120;
final (:isLoading, :isActive, :onPlay, :onShuffle) =
final (:isLoading, :isActive, :onPlay, :onShuffle, :onAddToQueue) =
useActionCallbacks(ref);
final playbackActions = Row(
@ -59,15 +59,15 @@ class TrackPresentationTopSection extends HookConsumerWidget {
child: IconButton.secondary(
icon: const Icon(SpotubeIcons.queueAdd),
enabled: !isLoading && !isActive,
onPressed: () {},
onPressed: onAddToQueue,
),
)
else
Button.secondary(
leading: const Icon(SpotubeIcons.add),
enabled: !isLoading && !isActive,
onPressed: onAddToQueue,
child: Text(context.l10n.queue),
onPressed: () {},
),
Button.primary(
alignment: Alignment.center,

View File

@ -1,8 +1,10 @@
import 'dart:math';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/dialogs/select_device_dialog.dart';
import 'package:spotube/components/track_presentation/presentation_actions.dart';
import 'package:spotube/components/track_presentation/presentation_props.dart';
import 'package:spotube/models/connect/connect.dart';
@ -17,6 +19,7 @@ typedef UseActionCallbacks = ({
bool isLoading,
Future<void> Function() onShuffle,
Future<void> Function() onPlay,
VoidCallback onAddToQueue,
});
UseActionCallbacks useActionCallbacks(WidgetRef ref) {
@ -96,6 +99,7 @@ UseActionCallbacks useActionCallbacks(WidgetRef ref) {
if (isRemoteDevice == null) return;
if (isRemoteDevice) {
final allTracks = await options.pagination.onFetchAll();
final remotePlayback = ref.read(connectProvider.notifier);
await remotePlayback.load(
options.collection is SpotubeSimpleAlbumObject
@ -109,14 +113,19 @@ UseActionCallbacks useActionCallbacks(WidgetRef ref) {
),
);
} else {
if (initialTracks.isEmpty) return;
await playlistNotifier.load(initialTracks, autoPlay: true);
playlistNotifier.addCollection(options.collectionId);
if (options.collection is SpotubeSimpleAlbumObject) {
historyNotifier
.addAlbums([options.collection as SpotubeSimpleAlbumObject]);
historyNotifier.addAlbums(
[options.collection as SpotubeSimpleAlbumObject],
);
} else {
historyNotifier.addPlaylists(
[options.collection as SpotubeSimplePlaylistObject]);
[options.collection as SpotubeSimplePlaylistObject],
);
}
final allTracks = await options.pagination.onFetchAll();
@ -132,10 +141,26 @@ UseActionCallbacks useActionCallbacks(WidgetRef ref) {
}
}, [options, playlistNotifier, historyNotifier]);
final onAddToQueue = useCallback(() {
final tracks = options.tracks;
playlistNotifier.addTracks(tracks);
playlistNotifier.addCollection(options.collectionId);
if (options.collection is SpotubeSimpleAlbumObject) {
historyNotifier
.addAlbums([options.collection as SpotubeSimpleAlbumObject]);
} else {
historyNotifier
.addPlaylists([options.collection as SpotubeSimplePlaylistObject]);
}
if (!context.mounted) return;
showToastForAction(context, "add-to-queue", tracks.length);
}, [options, playlistNotifier, historyNotifier]);
return (
isActive: isActive,
isLoading: isLoading.value,
onShuffle: onShuffle,
onPlay: onPlay,
onAddToQueue: onAddToQueue,
);
}

View File

@ -144,16 +144,21 @@ class AudioPlayerNotifier extends Notifier<AudioPlayerState> {
}),
audioPlayer.playlistStream.listen((playlist) async {
try {
// Playlist and state has to be in sync. This is only meant for
// the shuffle/re-ordering indices to be in sync
if (playlist.medias.length != state.tracks.length) return;
final queries = playlist.medias
.map((media) => TrackSourceQuery.parseUri(media.uri))
.toList();
final trackGroupedById = groupBy(
state.tracks,
(query) => query.id,
);
final tracks = queries
.map(
(query) => state.tracks.firstWhereOrNull(
(element) => element.id == query.id,
),
)
.map((query) => trackGroupedById[query.id]?.firstOrNull)
.nonNulls
.toList();
@ -269,12 +274,12 @@ class AudioPlayerNotifier extends Notifier<AudioPlayerState> {
_assertAllowedTracks(tracks);
tracks = _blacklist.filter(tracks).toList();
for (final track in tracks) {
await audioPlayer.addTrack(SpotubeMedia(track));
}
state = state.copyWith(
tracks: [...state.tracks, ...tracks],
);
for (final track in tracks) {
await audioPlayer.addTrack(SpotubeMedia(track));
}
}
Future<void> removeTrack(String trackId) async {