diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 7a648008..d11ae441 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -5948,6 +5948,18 @@ abstract class AppLocalizations { /// **'Keep'** String get cancelDownloadKeep; + /// Dialog title when opening a cancelled queue item + /// + /// In en, this message translates to: + /// **'Download cancelled'** + String get queueCancelledTitle; + + /// Dialog body when opening a cancelled queue item + /// + /// In en, this message translates to: + /// **'This download was cancelled. Retry it or remove it from the queue.'** + String get queueCancelledMessage; + /// Snackbar error when FFmpeg fails to write metadata /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 0adaed3b..032d44ca 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -3590,6 +3590,13 @@ class AppLocalizationsDe extends AppLocalizations { @override String get cancelDownloadKeep => 'Behalten'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Fehler beim Speichern der Metadaten über FFmpeg'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 2964a5a3..4d14a53f 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -3547,6 +3547,13 @@ class AppLocalizationsEn extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index a2cf80a3..73f285f7 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -3547,6 +3547,13 @@ class AppLocalizationsEs extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index f1d93a1e..8b50f585 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -3641,6 +3641,13 @@ class AppLocalizationsFr extends AppLocalizations { @override String get cancelDownloadKeep => 'Conserver'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Échec de l\'enregistrement des métadonnées via FFmpeg'; diff --git a/lib/l10n/app_localizations_id.dart b/lib/l10n/app_localizations_id.dart index 0681ee79..92fc66dd 100644 --- a/lib/l10n/app_localizations_id.dart +++ b/lib/l10n/app_localizations_id.dart @@ -3550,6 +3550,13 @@ class AppLocalizationsId extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 797b2f5c..4df93bc5 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -3536,6 +3536,13 @@ class AppLocalizationsJa extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index e8df0dde..95b4721d 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -3443,6 +3443,13 @@ class AppLocalizationsKo extends AppLocalizations { @override String get cancelDownloadKeep => '유지'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'FFmpeg를 통해 메타데이터 저장 실패'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 7bf39e1c..d2743294 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -3547,6 +3547,13 @@ class AppLocalizationsPt extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 3da28565..564e1980 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -3576,6 +3576,13 @@ class AppLocalizationsRu extends AppLocalizations { @override String get cancelDownloadKeep => 'Удерживать'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Не удалось сохранить метаданные через FFmpeg'; diff --git a/lib/l10n/app_localizations_tr.dart b/lib/l10n/app_localizations_tr.dart index ff987f33..32b488e2 100644 --- a/lib/l10n/app_localizations_tr.dart +++ b/lib/l10n/app_localizations_tr.dart @@ -3577,6 +3577,13 @@ class AppLocalizationsTr extends AppLocalizations { @override String get cancelDownloadKeep => 'Keep'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Failed to save metadata via FFmpeg'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 02206011..faadf8e1 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -3594,6 +3594,13 @@ class AppLocalizationsUk extends AppLocalizations { @override String get cancelDownloadKeep => 'Зберегти'; + @override + String get queueCancelledTitle => 'Download cancelled'; + + @override + String get queueCancelledMessage => + 'This download was cancelled. Retry it or remove it from the queue.'; + @override String get metadataSaveFailedFfmpeg => 'Не вдалося зберегти метадані через FFmpeg'; diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 4dd0af05..fb2eac57 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -4577,6 +4577,14 @@ "@cancelDownloadKeep": { "description": "Dialog button - keep the active download (do not cancel)" }, + "queueCancelledTitle": "Download cancelled", + "@queueCancelledTitle": { + "description": "Dialog title when opening a cancelled queue item" + }, + "queueCancelledMessage": "This download was cancelled. Retry it or remove it from the queue.", + "@queueCancelledMessage": { + "description": "Dialog body when opening a cancelled queue item" + }, "metadataSaveFailedFfmpeg": "Failed to save metadata via FFmpeg", "@metadataSaveFailedFfmpeg": { "description": "Snackbar error when FFmpeg fails to write metadata" diff --git a/lib/providers/download_queue_provider.dart b/lib/providers/download_queue_provider.dart index f35c2c4f..cc104f5e 100644 --- a/lib/providers/download_queue_provider.dart +++ b/lib/providers/download_queue_provider.dart @@ -261,7 +261,8 @@ class DownloadQueueNotifier extends Notifier { item.status == DownloadStatus.finalizing) { item = item.copyWith(status: DownloadStatus.queued, progress: 0); } - if (item.status == DownloadStatus.queued) { + if (item.status == DownloadStatus.queued || + item.status == DownloadStatus.skipped) { pendingItems.add(item); } } catch (_) { @@ -306,12 +307,15 @@ class DownloadQueueNotifier extends Notifier { Future _writeQueueChanges() async { try { + // skipped (user-cancelled) rows persist too, so a cancelled download can + // still be retried after an app restart instead of being re-searched. final pendingItems = state.items .where( (item) => item.status == DownloadStatus.queued || item.status == DownloadStatus.downloading || - item.status == DownloadStatus.finalizing, + item.status == DownloadStatus.finalizing || + item.status == DownloadStatus.skipped, ) .toList(growable: false); final nowIso = DateTime.now().toIso8601String(); diff --git a/lib/screens/queue_tab.dart b/lib/screens/queue_tab.dart index 1fc0966c..349b1b0a 100644 --- a/lib/screens/queue_tab.dart +++ b/lib/screens/queue_tab.dart @@ -1624,7 +1624,9 @@ class _QueueTabState extends ConsumerState { ), ); if (confirmed == true) { - ref.read(downloadQueueProvider.notifier).dismissItem(item.id); + // cancelItem (not dismissItem): the item stays in the queue as + // cancelled so it can be retried without re-searching the track. + ref.read(downloadQueueProvider.notifier).cancelItem(item.id); } } @@ -1634,13 +1636,18 @@ class _QueueTabState extends ConsumerState { ) async { final colorScheme = Theme.of(context).colorScheme; final isRateLimit = item.errorType == DownloadErrorType.rateLimit; + final isCancelled = item.status == DownloadStatus.skipped; final isFolderAccessLost = item.errorMessage == safPermissionLostErrorMessage || item.errorMessage == downloadFolderAccessLostErrorMessage; - final title = isRateLimit + final title = isCancelled + ? context.l10n.queueCancelledTitle + : isRateLimit ? context.l10n.queueRateLimitTitle : context.l10n.updateDownloadFailed; - final message = isRateLimit + final message = isCancelled + ? context.l10n.queueCancelledMessage + : isRateLimit ? context.l10n.queueRateLimitMessage : (item.errorMessage.trim().isNotEmpty ? _localizedDownloadError(context, item.errorMessage) diff --git a/lib/screens/queue_tab_collection_items.dart b/lib/screens/queue_tab_collection_items.dart index 6ccf87a4..fdebed9c 100644 --- a/lib/screens/queue_tab_collection_items.dart +++ b/lib/screens/queue_tab_collection_items.dart @@ -27,10 +27,8 @@ extension _QueueTabCollectionItemWidgets on _QueueTabState { child: Icon(Icons.music_note, color: colorScheme.onSurfaceVariant), ); - final onTap = isFailed + final onTap = isFailed || item.status == DownloadStatus.skipped ? () => _showDownloadErrorDialog(context, item) - : item.status == DownloadStatus.skipped - ? () => ref.read(downloadQueueProvider.notifier).removeItem(item.id) : () => _confirmCancelDownload(context, item); return SmoothedProgressScope(