mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-02 09:08:35 +02:00
feat(queue): long-press menu with move up/down for queued items
This commit is contained in:
@@ -6306,6 +6306,18 @@ abstract class AppLocalizations {
|
||||
/// **'Download next'**
|
||||
String get queueDownloadNext;
|
||||
|
||||
/// Queue item menu action - move the queued item one position earlier
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Move up'**
|
||||
String get queueMoveUp;
|
||||
|
||||
/// Queue item menu action - move the queued item one position later
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Move down'**
|
||||
String get queueMoveDown;
|
||||
|
||||
/// Tag editor button that fills genre and album artist from MusicBrainz by ISRC
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -3841,6 +3841,12 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3795,6 +3795,12 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3789,6 +3789,12 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3896,6 +3896,12 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3798,6 +3798,12 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3784,6 +3784,12 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3685,6 +3685,12 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3789,6 +3789,12 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3826,6 +3826,12 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3825,6 +3825,12 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -3843,6 +3843,12 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get queueDownloadNext => 'Download next';
|
||||
|
||||
@override
|
||||
String get queueMoveUp => 'Move up';
|
||||
|
||||
@override
|
||||
String get queueMoveDown => 'Move down';
|
||||
|
||||
@override
|
||||
String get editMetadataMusicBrainzButton => 'Fetch from MusicBrainz';
|
||||
|
||||
|
||||
@@ -4930,6 +4930,14 @@
|
||||
"@queueDownloadNext": {
|
||||
"description": "Tooltip on a queued download row; moves the item to the front of the queue so the next free slot downloads it"
|
||||
},
|
||||
"queueMoveUp": "Move up",
|
||||
"@queueMoveUp": {
|
||||
"description": "Queue item menu action - move the queued item one position earlier"
|
||||
},
|
||||
"queueMoveDown": "Move down",
|
||||
"@queueMoveDown": {
|
||||
"description": "Queue item menu action - move the queued item one position later"
|
||||
},
|
||||
"editMetadataMusicBrainzButton": "Fetch from MusicBrainz",
|
||||
"@editMetadataMusicBrainzButton": {
|
||||
"description": "Tag editor button that fills genre and album artist from MusicBrainz by ISRC"
|
||||
|
||||
@@ -1014,6 +1014,31 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
_saveQueueToStorage();
|
||||
}
|
||||
|
||||
/// Moves a queued item [offset] positions up (negative) or down (positive)
|
||||
/// among the queued items, leaving non-queued rows in place. Same native
|
||||
/// worker caveat as [downloadNext]: an in-flight batch keeps its order.
|
||||
void moveQueuedItem(String id, int offset) {
|
||||
if (offset == 0) return;
|
||||
final items = state.items;
|
||||
final index = items.indexWhere((item) => item.id == id);
|
||||
if (index == -1) return;
|
||||
final item = items[index];
|
||||
if (item.status != DownloadStatus.queued) return;
|
||||
final queuedIndices = <int>[
|
||||
for (var i = 0; i < items.length; i++)
|
||||
if (items[i].status == DownloadStatus.queued) i,
|
||||
];
|
||||
final position = queuedIndices.indexOf(index);
|
||||
final targetPosition = position + offset;
|
||||
if (targetPosition < 0 || targetPosition >= queuedIndices.length) return;
|
||||
final reordered = List<DownloadItem>.from(items)..removeAt(index);
|
||||
// Inserting at the target's pre-removal index lands the item directly
|
||||
// before it when moving up and directly after it when moving down.
|
||||
reordered.insert(queuedIndices[targetPosition], item);
|
||||
state = state.copyWith(items: reordered);
|
||||
_saveQueueToStorage();
|
||||
}
|
||||
|
||||
void removeItem(String id) {
|
||||
final removedItem = state.items.where((item) => item.id == id).firstOrNull;
|
||||
_locallyCancelledItemIds.remove(id);
|
||||
|
||||
@@ -194,9 +194,13 @@ extension _QueueTabItemWidgets on _QueueTabState {
|
||||
child: InkWell(
|
||||
onTap: isCompleted
|
||||
? () => _navigateToMetadataScreen(item)
|
||||
: item.status == DownloadStatus.failed
|
||||
: item.status == DownloadStatus.failed ||
|
||||
item.status == DownloadStatus.skipped
|
||||
? () => _showDownloadErrorDialog(context, item)
|
||||
: null,
|
||||
onLongPress: item.status == DownloadStatus.queued
|
||||
? () => _showQueuedItemMenu(context, item)
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Stack(
|
||||
children: [
|
||||
@@ -479,6 +483,45 @@ extension _QueueTabItemWidgets on _QueueTabState {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showQueuedItemMenu(BuildContext context, DownloadItem item) {
|
||||
final notifier = ref.read(downloadQueueProvider.notifier);
|
||||
return showModalBottomSheet<void>(
|
||||
context: context,
|
||||
showDragHandle: true,
|
||||
builder: (ctx) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.skip_next),
|
||||
title: Text(context.l10n.queueDownloadNext),
|
||||
onTap: () {
|
||||
Navigator.of(ctx).pop();
|
||||
notifier.downloadNext(item.id);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.arrow_upward),
|
||||
title: Text(context.l10n.queueMoveUp),
|
||||
onTap: () {
|
||||
Navigator.of(ctx).pop();
|
||||
notifier.moveQueuedItem(item.id, -1);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.arrow_downward),
|
||||
title: Text(context.l10n.queueMoveDown),
|
||||
onTap: () {
|
||||
Navigator.of(ctx).pop();
|
||||
notifier.moveQueuedItem(item.id, 1);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButtons(
|
||||
BuildContext context,
|
||||
DownloadItem item,
|
||||
|
||||
Reference in New Issue
Block a user