feat(queue): add track(s) for playing next (#460)

This commit is contained in:
Kingkor Roy Tirtho 2023-04-28 11:30:27 +06:00
parent 441b43bef6
commit cac8ea6388
4 changed files with 83 additions and 9 deletions

View File

@ -75,4 +75,5 @@ abstract class SpotubeIcons {
static const hoverOn = Icons.back_hand_rounded; static const hoverOn = Icons.back_hand_rounded;
static const hoverOff = Icons.back_hand_outlined; static const hoverOff = Icons.back_hand_outlined;
static const dragHandle = Icons.drag_indicator; static const dragHandle = Icons.drag_indicator;
static const lightning = Icons.flash_on_rounded;
} }

View File

@ -310,35 +310,55 @@ class TrackTile extends HookConsumerWidget {
tooltip: "More options", tooltip: "More options",
itemBuilder: (context) { itemBuilder: (context) {
return [ return [
if (!playlistQueueNotifier.isTrackOnQueue(track.value)) if (!playlistQueueNotifier.isTrackOnQueue(track.value)) ...[
PopupMenuItem( PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onTap: () { onTap: () {
playlistQueueNotifier.add([track.value]); playlistQueueNotifier.add([track.value]);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: content: Text(
Text("Added ${track.value.name} to queue"), "Added ${track.value.name} to queue",
),
), ),
); );
}, },
child: const ListTile( child: const ListTile(
leading: Icon(SpotubeIcons.queueAdd), leading: Icon(SpotubeIcons.queueAdd),
title: Text("Add to queue"), title: Text("Add to Queue"),
), ),
) ),
else
PopupMenuItem( PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onTap: () { onTap: () {
playlistQueueNotifier.remove([track.value]); playlistQueueNotifier.playNext([track.value]);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content:
"Removed ${track.value.name} from queue"), Text("${track.value.name} will play next"),
), ),
); );
}, },
child: const ListTile(
leading: Icon(SpotubeIcons.lightning),
title: Text("Play next"),
),
),
] else
PopupMenuItem(
padding: EdgeInsets.zero,
onTap: playlist?.activeTrack.id == track.value.id
? null
: () {
playlistQueueNotifier.remove([track.value]);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Removed ${track.value.name} from queue"),
),
);
},
enabled: playlist?.activeTrack.id != track.value.id,
child: const ListTile( child: const ListTile(
leading: Icon(SpotubeIcons.queueRemove), leading: Icon(SpotubeIcons.queueRemove),
title: Text("Remove from queue"), title: Text("Remove from queue"),

View File

@ -41,6 +41,7 @@ class TracksTableView extends HookConsumerWidget {
@override @override
Widget build(context, ref) { Widget build(context, ref) {
final playlist = ref.watch(PlaylistQueueNotifier.provider); final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final downloader = ref.watch(downloaderProvider); final downloader = ref.watch(downloaderProvider);
TextStyle tableHeadStyle = TextStyle tableHeadStyle =
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16); const TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
@ -162,6 +163,32 @@ class TracksTableView extends HookConsumerWidget {
], ],
), ),
), ),
PopupMenuItem(
enabled: selectedTracks.isNotEmpty,
value: "add-to-queue",
child: Row(
children: [
const Icon(SpotubeIcons.queueAdd),
const SizedBox(width: 5),
Text(
"Add (${selectedTracks.length}) to Queue",
),
],
),
),
PopupMenuItem(
enabled: selectedTracks.isNotEmpty,
value: "play-next",
child: Row(
children: [
const Icon(SpotubeIcons.lightning),
const SizedBox(width: 5),
Text(
"Play (${selectedTracks.length}) Next",
),
],
),
),
]; ];
}, },
onSelected: (action) async { onSelected: (action) async {
@ -194,6 +221,20 @@ class TracksTableView extends HookConsumerWidget {
); );
break; break;
} }
case "play-next":
{
playlistNotifier.playNext(selectedTracks.toList());
selected.value = [];
showCheck.value = false;
break;
}
case "add-to-queue":
{
playlistNotifier.add(selectedTracks.toList());
selected.value = [];
showCheck.value = false;
break;
}
default: default:
} }
}, },

View File

@ -266,6 +266,18 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
} }
} }
void playNext(List<Track> tracks) {
if (!isLoaded) {
loadAndPlay(tracks);
} else {
final stateTracks = state!.tracks.toList();
stateTracks.insertAll(state!.active + 1, tracks);
state = state?.copyWith(tracks: Set.from(stateTracks));
}
}
void remove(List<Track> tracks) { void remove(List<Track> tracks) {
if (!isLoaded) return; if (!isLoaded) return;
final trackIds = tracks.map((e) => e.id!).toSet(); final trackIds = tracks.map((e) => e.id!).toSet();