@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Kun usete",
|
"unwatchedOnly": "Kun usete",
|
||||||
"nextNUnwatched": "Næste ${count} usete",
|
"nextNUnwatched": "Næste ${count} usete",
|
||||||
"customAmount": "Angiv antal...",
|
"customAmount": "Angiv antal...",
|
||||||
"howManyEpisodes": "Hvor mange episoder?"
|
"howManyEpisodes": "Hvor mange episoder?",
|
||||||
|
"itemsQueued": "${count} elementer sat i kø til download"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shadere",
|
"title": "Shadere",
|
||||||
|
|||||||
@@ -635,7 +635,8 @@
|
|||||||
"unwatchedOnly": "Nur ungesehene",
|
"unwatchedOnly": "Nur ungesehene",
|
||||||
"nextNUnwatched": "Nächste ${count} ungesehene",
|
"nextNUnwatched": "Nächste ${count} ungesehene",
|
||||||
"customAmount": "Eigene Anzahl...",
|
"customAmount": "Eigene Anzahl...",
|
||||||
"howManyEpisodes": "Wie viele Episoden?"
|
"howManyEpisodes": "Wie viele Episoden?",
|
||||||
|
"itemsQueued": "${count} Elemente zum Download eingereiht"
|
||||||
},
|
},
|
||||||
"playlists": {
|
"playlists": {
|
||||||
"title": "Wiedergabelisten",
|
"title": "Wiedergabelisten",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Unwatched only",
|
"unwatchedOnly": "Unwatched only",
|
||||||
"nextNUnwatched": "Next ${count} unwatched",
|
"nextNUnwatched": "Next ${count} unwatched",
|
||||||
"customAmount": "Custom amount...",
|
"customAmount": "Custom amount...",
|
||||||
"howManyEpisodes": "How many episodes?"
|
"howManyEpisodes": "How many episodes?",
|
||||||
|
"itemsQueued": "${count} items queued for download"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shaders",
|
"title": "Shaders",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Solo no vistos",
|
"unwatchedOnly": "Solo no vistos",
|
||||||
"nextNUnwatched": "Próximos ${count} no vistos",
|
"nextNUnwatched": "Próximos ${count} no vistos",
|
||||||
"customAmount": "Cantidad personalizada...",
|
"customAmount": "Cantidad personalizada...",
|
||||||
"howManyEpisodes": "¿Cuántos episodios?"
|
"howManyEpisodes": "¿Cuántos episodios?",
|
||||||
|
"itemsQueued": "${count} elementos en cola de descarga"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shaders",
|
"title": "Shaders",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Non vus uniquement",
|
"unwatchedOnly": "Non vus uniquement",
|
||||||
"nextNUnwatched": "${count} prochains non vus",
|
"nextNUnwatched": "${count} prochains non vus",
|
||||||
"customAmount": "Quantité personnalisée...",
|
"customAmount": "Quantité personnalisée...",
|
||||||
"howManyEpisodes": "Combien d'épisodes ?"
|
"howManyEpisodes": "Combien d'épisodes ?",
|
||||||
|
"itemsQueued": "${count} éléments mis en file d'attente"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shaders",
|
"title": "Shaders",
|
||||||
|
|||||||
@@ -635,7 +635,8 @@
|
|||||||
"unwatchedOnly": "Solo non visti",
|
"unwatchedOnly": "Solo non visti",
|
||||||
"nextNUnwatched": "Prossimi ${count} non visti",
|
"nextNUnwatched": "Prossimi ${count} non visti",
|
||||||
"customAmount": "Quantità personalizzata...",
|
"customAmount": "Quantità personalizzata...",
|
||||||
"howManyEpisodes": "Quanti episodi?"
|
"howManyEpisodes": "Quanti episodi?",
|
||||||
|
"itemsQueued": "${count} elementi in coda per il download"
|
||||||
},
|
},
|
||||||
"playlists": {
|
"playlists": {
|
||||||
"title": "Playlist",
|
"title": "Playlist",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "未視聴のみ",
|
"unwatchedOnly": "未視聴のみ",
|
||||||
"nextNUnwatched": "次の${count}件の未視聴",
|
"nextNUnwatched": "次の${count}件の未視聴",
|
||||||
"customAmount": "数を指定...",
|
"customAmount": "数を指定...",
|
||||||
"howManyEpisodes": "何エピソード?"
|
"howManyEpisodes": "何エピソード?",
|
||||||
|
"itemsQueued": "${count}件をダウンロードキューに追加"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "シェーダー",
|
"title": "シェーダー",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "시청하지 않은 것만",
|
"unwatchedOnly": "시청하지 않은 것만",
|
||||||
"nextNUnwatched": "다음 ${count}개 미시청",
|
"nextNUnwatched": "다음 ${count}개 미시청",
|
||||||
"customAmount": "직접 입력...",
|
"customAmount": "직접 입력...",
|
||||||
"howManyEpisodes": "몇 개의 에피소드?"
|
"howManyEpisodes": "몇 개의 에피소드?",
|
||||||
|
"itemsQueued": "${count}개 항목이 다운로드 대기열에 추가됨"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "셰이더",
|
"title": "셰이더",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Kun usette",
|
"unwatchedOnly": "Kun usette",
|
||||||
"nextNUnwatched": "Neste ${count} usette",
|
"nextNUnwatched": "Neste ${count} usette",
|
||||||
"customAmount": "Egendefinert antall...",
|
"customAmount": "Egendefinert antall...",
|
||||||
"howManyEpisodes": "Hvor mange episoder?"
|
"howManyEpisodes": "Hvor mange episoder?",
|
||||||
|
"itemsQueued": "${count} elementer i nedlastingskø"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shadere",
|
"title": "Shadere",
|
||||||
|
|||||||
@@ -635,7 +635,8 @@
|
|||||||
"unwatchedOnly": "Alleen onbekeken",
|
"unwatchedOnly": "Alleen onbekeken",
|
||||||
"nextNUnwatched": "Volgende ${count} onbekeken",
|
"nextNUnwatched": "Volgende ${count} onbekeken",
|
||||||
"customAmount": "Aangepast aantal...",
|
"customAmount": "Aangepast aantal...",
|
||||||
"howManyEpisodes": "Hoeveel afleveringen?"
|
"howManyEpisodes": "Hoeveel afleveringen?",
|
||||||
|
"itemsQueued": "${count} items in downloadwachtrij"
|
||||||
},
|
},
|
||||||
"playlists": {
|
"playlists": {
|
||||||
"title": "Afspeellijsten",
|
"title": "Afspeellijsten",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Tylko nieobejrzane",
|
"unwatchedOnly": "Tylko nieobejrzane",
|
||||||
"nextNUnwatched": "Następne ${count} nieobejrzanych",
|
"nextNUnwatched": "Następne ${count} nieobejrzanych",
|
||||||
"customAmount": "Własna ilość...",
|
"customAmount": "Własna ilość...",
|
||||||
"howManyEpisodes": "Ile odcinków?"
|
"howManyEpisodes": "Ile odcinków?",
|
||||||
|
"itemsQueued": "${count} elementów dodanych do kolejki pobierania"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shadery",
|
"title": "Shadery",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Apenas não assistidos",
|
"unwatchedOnly": "Apenas não assistidos",
|
||||||
"nextNUnwatched": "Próximos ${count} não assistidos",
|
"nextNUnwatched": "Próximos ${count} não assistidos",
|
||||||
"customAmount": "Quantidade personalizada...",
|
"customAmount": "Quantidade personalizada...",
|
||||||
"howManyEpisodes": "Quantos episódios?"
|
"howManyEpisodes": "Quantos episódios?",
|
||||||
|
"itemsQueued": "${count} itens na fila de download"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Shaders",
|
"title": "Shaders",
|
||||||
|
|||||||
@@ -738,7 +738,8 @@
|
|||||||
"unwatchedOnly": "Только непросмотренные",
|
"unwatchedOnly": "Только непросмотренные",
|
||||||
"nextNUnwatched": "Следующие ${count} непросмотренных",
|
"nextNUnwatched": "Следующие ${count} непросмотренных",
|
||||||
"customAmount": "Указать количество...",
|
"customAmount": "Указать количество...",
|
||||||
"howManyEpisodes": "Сколько эпизодов?"
|
"howManyEpisodes": "Сколько эпизодов?",
|
||||||
|
"itemsQueued": "${count} элементов добавлено в очередь загрузки"
|
||||||
},
|
},
|
||||||
"shaders": {
|
"shaders": {
|
||||||
"title": "Шейдеры",
|
"title": "Шейдеры",
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
/// To regenerate, run: `dart run slang`
|
/// To regenerate, run: `dart run slang`
|
||||||
///
|
///
|
||||||
/// Locales: 15
|
/// Locales: 15
|
||||||
/// Strings: 12825 (855 per locale)
|
/// Strings: 12840 (856 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2026-04-07 at 18:27 UTC
|
/// Built on 2026-04-08 at 10:00 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint, unused_import
|
// ignore_for_file: type=lint, unused_import
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsDa implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Næste ${count} usete';
|
@override String nextNUnwatched({required Object count}) => 'Næste ${count} usete';
|
||||||
@override String get customAmount => 'Angiv antal...';
|
@override String get customAmount => 'Angiv antal...';
|
||||||
@override String get howManyEpisodes => 'Hvor mange episoder?';
|
@override String get howManyEpisodes => 'Hvor mange episoder?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} elementer sat i kø til download';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsDa {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Næste ${count} usete',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Næste ${count} usete',
|
||||||
'downloads.customAmount' => 'Angiv antal...',
|
'downloads.customAmount' => 'Angiv antal...',
|
||||||
'downloads.howManyEpisodes' => 'Hvor mange episoder?',
|
'downloads.howManyEpisodes' => 'Hvor mange episoder?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} elementer sat i kø til download',
|
||||||
'shaders.title' => 'Shadere',
|
'shaders.title' => 'Shadere',
|
||||||
'shaders.noShaderDescription' => 'Ingen videoforbedring',
|
'shaders.noShaderDescription' => 'Ingen videoforbedring',
|
||||||
'shaders.nvscalerDescription' => 'NVIDIA-billedskalering for skarpere video',
|
'shaders.nvscalerDescription' => 'NVIDIA-billedskalering for skarpere video',
|
||||||
|
|||||||
@@ -875,6 +875,7 @@ class _TranslationsDownloadsDe implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Nächste ${count} ungesehene';
|
@override String nextNUnwatched({required Object count}) => 'Nächste ${count} ungesehene';
|
||||||
@override String get customAmount => 'Eigene Anzahl...';
|
@override String get customAmount => 'Eigene Anzahl...';
|
||||||
@override String get howManyEpisodes => 'Wie viele Episoden?';
|
@override String get howManyEpisodes => 'Wie viele Episoden?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} Elemente zum Download eingereiht';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: playlists
|
// Path: playlists
|
||||||
@@ -1926,6 +1927,7 @@ extension on TranslationsDe {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Nächste ${count} ungesehene',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Nächste ${count} ungesehene',
|
||||||
'downloads.customAmount' => 'Eigene Anzahl...',
|
'downloads.customAmount' => 'Eigene Anzahl...',
|
||||||
'downloads.howManyEpisodes' => 'Wie viele Episoden?',
|
'downloads.howManyEpisodes' => 'Wie viele Episoden?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} Elemente zum Download eingereiht',
|
||||||
'playlists.title' => 'Wiedergabelisten',
|
'playlists.title' => 'Wiedergabelisten',
|
||||||
'playlists.noPlaylists' => 'Keine Wiedergabelisten gefunden',
|
'playlists.noPlaylists' => 'Keine Wiedergabelisten gefunden',
|
||||||
'playlists.create' => 'Wiedergabeliste erstellen',
|
'playlists.create' => 'Wiedergabeliste erstellen',
|
||||||
|
|||||||
@@ -2269,6 +2269,9 @@ class TranslationsDownloadsEn {
|
|||||||
|
|
||||||
/// en: 'How many episodes?'
|
/// en: 'How many episodes?'
|
||||||
String get howManyEpisodes => 'How many episodes?';
|
String get howManyEpisodes => 'How many episodes?';
|
||||||
|
|
||||||
|
/// en: '${count} items queued for download'
|
||||||
|
String itemsQueued({required Object count}) => '${count} items queued for download';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -3740,6 +3743,7 @@ extension on Translations {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Next ${count} unwatched',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Next ${count} unwatched',
|
||||||
'downloads.customAmount' => 'Custom amount...',
|
'downloads.customAmount' => 'Custom amount...',
|
||||||
'downloads.howManyEpisodes' => 'How many episodes?',
|
'downloads.howManyEpisodes' => 'How many episodes?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} items queued for download',
|
||||||
'shaders.title' => 'Shaders',
|
'shaders.title' => 'Shaders',
|
||||||
'shaders.noShaderDescription' => 'No video enhancement',
|
'shaders.noShaderDescription' => 'No video enhancement',
|
||||||
'shaders.nvscalerDescription' => 'NVIDIA image scaling for sharper video',
|
'shaders.nvscalerDescription' => 'NVIDIA image scaling for sharper video',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsEs implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Próximos ${count} no vistos';
|
@override String nextNUnwatched({required Object count}) => 'Próximos ${count} no vistos';
|
||||||
@override String get customAmount => 'Cantidad personalizada...';
|
@override String get customAmount => 'Cantidad personalizada...';
|
||||||
@override String get howManyEpisodes => '¿Cuántos episodios?';
|
@override String get howManyEpisodes => '¿Cuántos episodios?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} elementos en cola de descarga';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsEs {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Próximos ${count} no vistos',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Próximos ${count} no vistos',
|
||||||
'downloads.customAmount' => 'Cantidad personalizada...',
|
'downloads.customAmount' => 'Cantidad personalizada...',
|
||||||
'downloads.howManyEpisodes' => '¿Cuántos episodios?',
|
'downloads.howManyEpisodes' => '¿Cuántos episodios?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} elementos en cola de descarga',
|
||||||
'shaders.title' => 'Shaders',
|
'shaders.title' => 'Shaders',
|
||||||
'shaders.noShaderDescription' => 'Sin mejora de video',
|
'shaders.noShaderDescription' => 'Sin mejora de video',
|
||||||
'shaders.nvscalerDescription' => 'Escalado de imagen NVIDIA para un video más nítido',
|
'shaders.nvscalerDescription' => 'Escalado de imagen NVIDIA para un video más nítido',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsFr implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => '${count} prochains non vus';
|
@override String nextNUnwatched({required Object count}) => '${count} prochains non vus';
|
||||||
@override String get customAmount => 'Quantité personnalisée...';
|
@override String get customAmount => 'Quantité personnalisée...';
|
||||||
@override String get howManyEpisodes => 'Combien d\'épisodes ?';
|
@override String get howManyEpisodes => 'Combien d\'épisodes ?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} éléments mis en file d\'attente';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsFr {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => '${count} prochains non vus',
|
'downloads.nextNUnwatched' => ({required Object count}) => '${count} prochains non vus',
|
||||||
'downloads.customAmount' => 'Quantité personnalisée...',
|
'downloads.customAmount' => 'Quantité personnalisée...',
|
||||||
'downloads.howManyEpisodes' => 'Combien d\'épisodes ?',
|
'downloads.howManyEpisodes' => 'Combien d\'épisodes ?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} éléments mis en file d\'attente',
|
||||||
'shaders.title' => 'Shaders',
|
'shaders.title' => 'Shaders',
|
||||||
'shaders.noShaderDescription' => 'Aucune amélioration vidéo',
|
'shaders.noShaderDescription' => 'Aucune amélioration vidéo',
|
||||||
'shaders.nvscalerDescription' => 'Mise à l\'échelle NVIDIA pour une vidéo plus nette',
|
'shaders.nvscalerDescription' => 'Mise à l\'échelle NVIDIA pour une vidéo plus nette',
|
||||||
|
|||||||
@@ -875,6 +875,7 @@ class _TranslationsDownloadsIt implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Prossimi ${count} non visti';
|
@override String nextNUnwatched({required Object count}) => 'Prossimi ${count} non visti';
|
||||||
@override String get customAmount => 'Quantità personalizzata...';
|
@override String get customAmount => 'Quantità personalizzata...';
|
||||||
@override String get howManyEpisodes => 'Quanti episodi?';
|
@override String get howManyEpisodes => 'Quanti episodi?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} elementi in coda per il download';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: playlists
|
// Path: playlists
|
||||||
@@ -1926,6 +1927,7 @@ extension on TranslationsIt {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Prossimi ${count} non visti',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Prossimi ${count} non visti',
|
||||||
'downloads.customAmount' => 'Quantità personalizzata...',
|
'downloads.customAmount' => 'Quantità personalizzata...',
|
||||||
'downloads.howManyEpisodes' => 'Quanti episodi?',
|
'downloads.howManyEpisodes' => 'Quanti episodi?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} elementi in coda per il download',
|
||||||
'playlists.title' => 'Playlist',
|
'playlists.title' => 'Playlist',
|
||||||
'playlists.noPlaylists' => 'Nessuna playlist trovata',
|
'playlists.noPlaylists' => 'Nessuna playlist trovata',
|
||||||
'playlists.create' => 'Crea playlist',
|
'playlists.create' => 'Crea playlist',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsJa implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => '次の${count}件の未視聴';
|
@override String nextNUnwatched({required Object count}) => '次の${count}件の未視聴';
|
||||||
@override String get customAmount => '数を指定...';
|
@override String get customAmount => '数を指定...';
|
||||||
@override String get howManyEpisodes => '何エピソード?';
|
@override String get howManyEpisodes => '何エピソード?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count}件をダウンロードキューに追加';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsJa {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => '次の${count}件の未視聴',
|
'downloads.nextNUnwatched' => ({required Object count}) => '次の${count}件の未視聴',
|
||||||
'downloads.customAmount' => '数を指定...',
|
'downloads.customAmount' => '数を指定...',
|
||||||
'downloads.howManyEpisodes' => '何エピソード?',
|
'downloads.howManyEpisodes' => '何エピソード?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count}件をダウンロードキューに追加',
|
||||||
'shaders.title' => 'シェーダー',
|
'shaders.title' => 'シェーダー',
|
||||||
'shaders.noShaderDescription' => '映像補正なし',
|
'shaders.noShaderDescription' => '映像補正なし',
|
||||||
'shaders.nvscalerDescription' => 'よりシャープな映像のためのNVIDIA画像スケーリング',
|
'shaders.nvscalerDescription' => 'よりシャープな映像のためのNVIDIA画像スケーリング',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsKo implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => '다음 ${count}개 미시청';
|
@override String nextNUnwatched({required Object count}) => '다음 ${count}개 미시청';
|
||||||
@override String get customAmount => '직접 입력...';
|
@override String get customAmount => '직접 입력...';
|
||||||
@override String get howManyEpisodes => '몇 개의 에피소드?';
|
@override String get howManyEpisodes => '몇 개의 에피소드?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count}개 항목이 다운로드 대기열에 추가됨';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsKo {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => '다음 ${count}개 미시청',
|
'downloads.nextNUnwatched' => ({required Object count}) => '다음 ${count}개 미시청',
|
||||||
'downloads.customAmount' => '직접 입력...',
|
'downloads.customAmount' => '직접 입력...',
|
||||||
'downloads.howManyEpisodes' => '몇 개의 에피소드?',
|
'downloads.howManyEpisodes' => '몇 개의 에피소드?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count}개 항목이 다운로드 대기열에 추가됨',
|
||||||
'shaders.title' => '셰이더',
|
'shaders.title' => '셰이더',
|
||||||
'shaders.noShaderDescription' => '비디오 향상 없음',
|
'shaders.noShaderDescription' => '비디오 향상 없음',
|
||||||
'shaders.nvscalerDescription' => '더 선명한 비디오를 위한 NVIDIA 이미지 스케일링',
|
'shaders.nvscalerDescription' => '더 선명한 비디오를 위한 NVIDIA 이미지 스케일링',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsNb implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Neste ${count} usette';
|
@override String nextNUnwatched({required Object count}) => 'Neste ${count} usette';
|
||||||
@override String get customAmount => 'Egendefinert antall...';
|
@override String get customAmount => 'Egendefinert antall...';
|
||||||
@override String get howManyEpisodes => 'Hvor mange episoder?';
|
@override String get howManyEpisodes => 'Hvor mange episoder?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} elementer i nedlastingskø';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsNb {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Neste ${count} usette',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Neste ${count} usette',
|
||||||
'downloads.customAmount' => 'Egendefinert antall...',
|
'downloads.customAmount' => 'Egendefinert antall...',
|
||||||
'downloads.howManyEpisodes' => 'Hvor mange episoder?',
|
'downloads.howManyEpisodes' => 'Hvor mange episoder?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} elementer i nedlastingskø',
|
||||||
'shaders.title' => 'Shadere',
|
'shaders.title' => 'Shadere',
|
||||||
'shaders.noShaderDescription' => 'Ingen videoforbedring',
|
'shaders.noShaderDescription' => 'Ingen videoforbedring',
|
||||||
'shaders.nvscalerDescription' => 'NVIDIA bildeskalering for skarpere video',
|
'shaders.nvscalerDescription' => 'NVIDIA bildeskalering for skarpere video',
|
||||||
|
|||||||
@@ -875,6 +875,7 @@ class _TranslationsDownloadsNl implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Volgende ${count} onbekeken';
|
@override String nextNUnwatched({required Object count}) => 'Volgende ${count} onbekeken';
|
||||||
@override String get customAmount => 'Aangepast aantal...';
|
@override String get customAmount => 'Aangepast aantal...';
|
||||||
@override String get howManyEpisodes => 'Hoeveel afleveringen?';
|
@override String get howManyEpisodes => 'Hoeveel afleveringen?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} items in downloadwachtrij';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: playlists
|
// Path: playlists
|
||||||
@@ -1926,6 +1927,7 @@ extension on TranslationsNl {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Volgende ${count} onbekeken',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Volgende ${count} onbekeken',
|
||||||
'downloads.customAmount' => 'Aangepast aantal...',
|
'downloads.customAmount' => 'Aangepast aantal...',
|
||||||
'downloads.howManyEpisodes' => 'Hoeveel afleveringen?',
|
'downloads.howManyEpisodes' => 'Hoeveel afleveringen?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} items in downloadwachtrij',
|
||||||
'playlists.title' => 'Afspeellijsten',
|
'playlists.title' => 'Afspeellijsten',
|
||||||
'playlists.noPlaylists' => 'Geen afspeellijsten gevonden',
|
'playlists.noPlaylists' => 'Geen afspeellijsten gevonden',
|
||||||
'playlists.create' => 'Afspeellijst maken',
|
'playlists.create' => 'Afspeellijst maken',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsPl implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Następne ${count} nieobejrzanych';
|
@override String nextNUnwatched({required Object count}) => 'Następne ${count} nieobejrzanych';
|
||||||
@override String get customAmount => 'Własna ilość...';
|
@override String get customAmount => 'Własna ilość...';
|
||||||
@override String get howManyEpisodes => 'Ile odcinków?';
|
@override String get howManyEpisodes => 'Ile odcinków?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} elementów dodanych do kolejki pobierania';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsPl {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Następne ${count} nieobejrzanych',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Następne ${count} nieobejrzanych',
|
||||||
'downloads.customAmount' => 'Własna ilość...',
|
'downloads.customAmount' => 'Własna ilość...',
|
||||||
'downloads.howManyEpisodes' => 'Ile odcinków?',
|
'downloads.howManyEpisodes' => 'Ile odcinków?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} elementów dodanych do kolejki pobierania',
|
||||||
'shaders.title' => 'Shadery',
|
'shaders.title' => 'Shadery',
|
||||||
'shaders.noShaderDescription' => 'Bez ulepszenia wideo',
|
'shaders.noShaderDescription' => 'Bez ulepszenia wideo',
|
||||||
'shaders.nvscalerDescription' => 'Skalowanie obrazu NVIDIA dla ostrzejszego wideo',
|
'shaders.nvscalerDescription' => 'Skalowanie obrazu NVIDIA dla ostrzejszego wideo',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsPt implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Próximos ${count} não assistidos';
|
@override String nextNUnwatched({required Object count}) => 'Próximos ${count} não assistidos';
|
||||||
@override String get customAmount => 'Quantidade personalizada...';
|
@override String get customAmount => 'Quantidade personalizada...';
|
||||||
@override String get howManyEpisodes => 'Quantos episódios?';
|
@override String get howManyEpisodes => 'Quantos episódios?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} itens na fila de download';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsPt {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Próximos ${count} não assistidos',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Próximos ${count} não assistidos',
|
||||||
'downloads.customAmount' => 'Quantidade personalizada...',
|
'downloads.customAmount' => 'Quantidade personalizada...',
|
||||||
'downloads.howManyEpisodes' => 'Quantos episódios?',
|
'downloads.howManyEpisodes' => 'Quantos episódios?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} itens na fila de download',
|
||||||
'shaders.title' => 'Shaders',
|
'shaders.title' => 'Shaders',
|
||||||
'shaders.noShaderDescription' => 'Sem aprimoramento de vídeo',
|
'shaders.noShaderDescription' => 'Sem aprimoramento de vídeo',
|
||||||
'shaders.nvscalerDescription' => 'Escalonamento de imagem NVIDIA para vídeo mais nítido',
|
'shaders.nvscalerDescription' => 'Escalonamento de imagem NVIDIA para vídeo mais nítido',
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ class _TranslationsDownloadsRu implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Следующие ${count} непросмотренных';
|
@override String nextNUnwatched({required Object count}) => 'Следующие ${count} непросмотренных';
|
||||||
@override String get customAmount => 'Указать количество...';
|
@override String get customAmount => 'Указать количество...';
|
||||||
@override String get howManyEpisodes => 'Сколько эпизодов?';
|
@override String get howManyEpisodes => 'Сколько эпизодов?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} элементов добавлено в очередь загрузки';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: shaders
|
// Path: shaders
|
||||||
@@ -2023,6 +2024,7 @@ extension on TranslationsRu {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Следующие ${count} непросмотренных',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Следующие ${count} непросмотренных',
|
||||||
'downloads.customAmount' => 'Указать количество...',
|
'downloads.customAmount' => 'Указать количество...',
|
||||||
'downloads.howManyEpisodes' => 'Сколько эпизодов?',
|
'downloads.howManyEpisodes' => 'Сколько эпизодов?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} элементов добавлено в очередь загрузки',
|
||||||
'shaders.title' => 'Шейдеры',
|
'shaders.title' => 'Шейдеры',
|
||||||
'shaders.noShaderDescription' => 'Без улучшения видео',
|
'shaders.noShaderDescription' => 'Без улучшения видео',
|
||||||
'shaders.nvscalerDescription' => 'Масштабирование NVIDIA для более чёткого видео',
|
'shaders.nvscalerDescription' => 'Масштабирование NVIDIA для более чёткого видео',
|
||||||
|
|||||||
@@ -875,6 +875,7 @@ class _TranslationsDownloadsSv implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => 'Nästa ${count} osedda';
|
@override String nextNUnwatched({required Object count}) => 'Nästa ${count} osedda';
|
||||||
@override String get customAmount => 'Ange antal...';
|
@override String get customAmount => 'Ange antal...';
|
||||||
@override String get howManyEpisodes => 'Hur många avsnitt?';
|
@override String get howManyEpisodes => 'Hur många avsnitt?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} objekt köade för nedladdning';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: playlists
|
// Path: playlists
|
||||||
@@ -1926,6 +1927,7 @@ extension on TranslationsSv {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => 'Nästa ${count} osedda',
|
'downloads.nextNUnwatched' => ({required Object count}) => 'Nästa ${count} osedda',
|
||||||
'downloads.customAmount' => 'Ange antal...',
|
'downloads.customAmount' => 'Ange antal...',
|
||||||
'downloads.howManyEpisodes' => 'Hur många avsnitt?',
|
'downloads.howManyEpisodes' => 'Hur många avsnitt?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} objekt köade för nedladdning',
|
||||||
'playlists.title' => 'Spellistor',
|
'playlists.title' => 'Spellistor',
|
||||||
'playlists.noPlaylists' => 'Inga spellistor hittades',
|
'playlists.noPlaylists' => 'Inga spellistor hittades',
|
||||||
'playlists.create' => 'Skapa spellista',
|
'playlists.create' => 'Skapa spellista',
|
||||||
|
|||||||
@@ -875,6 +875,7 @@ class _TranslationsDownloadsZh implements TranslationsDownloadsEn {
|
|||||||
@override String nextNUnwatched({required Object count}) => '接下来 ${count} 集未观看';
|
@override String nextNUnwatched({required Object count}) => '接下来 ${count} 集未观看';
|
||||||
@override String get customAmount => '自定义数量...';
|
@override String get customAmount => '自定义数量...';
|
||||||
@override String get howManyEpisodes => '下载几集?';
|
@override String get howManyEpisodes => '下载几集?';
|
||||||
|
@override String itemsQueued({required Object count}) => '${count} 个项目已加入下载队列';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: playlists
|
// Path: playlists
|
||||||
@@ -1926,6 +1927,7 @@ extension on TranslationsZh {
|
|||||||
'downloads.nextNUnwatched' => ({required Object count}) => '接下来 ${count} 集未观看',
|
'downloads.nextNUnwatched' => ({required Object count}) => '接下来 ${count} 集未观看',
|
||||||
'downloads.customAmount' => '自定义数量...',
|
'downloads.customAmount' => '自定义数量...',
|
||||||
'downloads.howManyEpisodes' => '下载几集?',
|
'downloads.howManyEpisodes' => '下载几集?',
|
||||||
|
'downloads.itemsQueued' => ({required Object count}) => '${count} 个项目已加入下载队列',
|
||||||
'playlists.title' => '播放列表',
|
'playlists.title' => '播放列表',
|
||||||
'playlists.noPlaylists' => '未找到播放列表',
|
'playlists.noPlaylists' => '未找到播放列表',
|
||||||
'playlists.create' => '创建播放列表',
|
'playlists.create' => '创建播放列表',
|
||||||
|
|||||||
@@ -635,7 +635,8 @@
|
|||||||
"unwatchedOnly": "Endast osedda",
|
"unwatchedOnly": "Endast osedda",
|
||||||
"nextNUnwatched": "Nästa ${count} osedda",
|
"nextNUnwatched": "Nästa ${count} osedda",
|
||||||
"customAmount": "Ange antal...",
|
"customAmount": "Ange antal...",
|
||||||
"howManyEpisodes": "Hur många avsnitt?"
|
"howManyEpisodes": "Hur många avsnitt?",
|
||||||
|
"itemsQueued": "${count} objekt köade för nedladdning"
|
||||||
},
|
},
|
||||||
"playlists": {
|
"playlists": {
|
||||||
"title": "Spellistor",
|
"title": "Spellistor",
|
||||||
|
|||||||
@@ -635,7 +635,8 @@
|
|||||||
"unwatchedOnly": "仅未观看",
|
"unwatchedOnly": "仅未观看",
|
||||||
"nextNUnwatched": "接下来 ${count} 集未观看",
|
"nextNUnwatched": "接下来 ${count} 集未观看",
|
||||||
"customAmount": "自定义数量...",
|
"customAmount": "自定义数量...",
|
||||||
"howManyEpisodes": "下载几集?"
|
"howManyEpisodes": "下载几集?",
|
||||||
|
"itemsQueued": "${count} 个项目已加入下载队列"
|
||||||
},
|
},
|
||||||
"playlists": {
|
"playlists": {
|
||||||
"title": "播放列表",
|
"title": "播放列表",
|
||||||
|
|||||||
@@ -639,6 +639,29 @@ class DownloadProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue all video items from a playlist for download.
|
||||||
|
/// Returns the number of items queued.
|
||||||
|
Future<int> queuePlaylistDownload(
|
||||||
|
List<PlexMetadata> items,
|
||||||
|
PlexClient client, {
|
||||||
|
DownloadFilter filter = DownloadFilter.all,
|
||||||
|
}) async {
|
||||||
|
if (await DownloadManagerService.shouldBlockDownloadOnCellular()) {
|
||||||
|
throw CellularDownloadBlockedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (final item in items) {
|
||||||
|
final mt = item.mediaType;
|
||||||
|
if (mt != PlexMediaType.movie && mt != PlexMediaType.episode) continue;
|
||||||
|
if (filter == DownloadFilter.unwatched && item.isWatched && !item.hasActiveProgress) continue;
|
||||||
|
|
||||||
|
final queued = await _queueSingleDownload(item, client);
|
||||||
|
if (queued) count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/// Queue a single movie or episode for download.
|
/// Queue a single movie or episode for download.
|
||||||
/// Returns true if the item was actually queued, false if skipped.
|
/// Returns true if the item was actually queued, false if skipped.
|
||||||
Future<bool> _queueSingleDownload(
|
Future<bool> _queueSingleDownload(
|
||||||
|
|||||||
@@ -13,9 +13,12 @@ import '../../widgets/desktop_app_bar.dart';
|
|||||||
import '../../focus/dpad_navigator.dart';
|
import '../../focus/dpad_navigator.dart';
|
||||||
import '../../focus/input_mode_tracker.dart';
|
import '../../focus/input_mode_tracker.dart';
|
||||||
import '../../focus/key_event_utils.dart';
|
import '../../focus/key_event_utils.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'playlist_item_card.dart';
|
import 'playlist_item_card.dart';
|
||||||
import '../../i18n/strings.g.dart';
|
import '../../i18n/strings.g.dart';
|
||||||
|
import '../../providers/download_provider.dart';
|
||||||
import '../../utils/dialogs.dart';
|
import '../../utils/dialogs.dart';
|
||||||
|
import '../../utils/download_utils.dart';
|
||||||
import '../../utils/snackbar_helper.dart';
|
import '../../utils/snackbar_helper.dart';
|
||||||
import '../base_media_list_detail_screen.dart';
|
import '../base_media_list_detail_screen.dart';
|
||||||
import '../focusable_detail_screen_mixin.dart';
|
import '../focusable_detail_screen_mixin.dart';
|
||||||
@@ -58,6 +61,8 @@ class _PlaylistDetailScreenState extends BaseMediaListDetailScreen<PlaylistDetai
|
|||||||
FocusableAction(icon: Symbols.play_arrow_rounded, tooltip: t.common.play, onPressed: playItems),
|
FocusableAction(icon: Symbols.play_arrow_rounded, tooltip: t.common.play, onPressed: playItems),
|
||||||
FocusableAction(icon: Symbols.shuffle_rounded, tooltip: t.common.shuffle, onPressed: shufflePlayItems),
|
FocusableAction(icon: Symbols.shuffle_rounded, tooltip: t.common.shuffle, onPressed: shufflePlayItems),
|
||||||
],
|
],
|
||||||
|
if (items.isNotEmpty && widget.playlist.playlistType == 'video')
|
||||||
|
FocusableAction(icon: Symbols.download_rounded, tooltip: t.downloads.downloadNow, onPressed: _downloadPlaylist),
|
||||||
if (!widget.playlist.smart)
|
if (!widget.playlist.smart)
|
||||||
FocusableAction(icon: Symbols.delete_rounded, tooltip: t.playlists.delete, onPressed: _deletePlaylist, iconColor: Colors.red),
|
FocusableAction(icon: Symbols.delete_rounded, tooltip: t.playlists.delete, onPressed: _deletePlaylist, iconColor: Colors.red),
|
||||||
];
|
];
|
||||||
@@ -139,6 +144,31 @@ class _PlaylistDetailScreenState extends BaseMediaListDetailScreen<PlaylistDetai
|
|||||||
return context.getClientForServer(widget.playlist.serverId!);
|
return context.getClientForServer(widget.playlist.serverId!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _downloadPlaylist() async {
|
||||||
|
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final count = await showPlaylistDownloadOptionsAndQueue(
|
||||||
|
context,
|
||||||
|
items: items,
|
||||||
|
client: client,
|
||||||
|
downloadProvider: downloadProvider,
|
||||||
|
);
|
||||||
|
if (count == null || !mounted) return;
|
||||||
|
|
||||||
|
final message = count > 1 ? t.downloads.itemsQueued(count: count) : t.downloads.downloadQueued;
|
||||||
|
showSuccessSnackBar(context, message);
|
||||||
|
} on CellularDownloadBlockedException {
|
||||||
|
if (mounted) {
|
||||||
|
showErrorSnackBar(context, t.settings.cellularDownloadBlocked);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
showErrorSnackBar(context, t.messages.errorLoading(error: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _deletePlaylist() async {
|
Future<void> _deletePlaylist() async {
|
||||||
final confirmed = await showDeleteConfirmation(
|
final confirmed = await showDeleteConfirmation(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -75,6 +75,32 @@ Future<int?> showDownloadOptionsAndQueue(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows download options dialog for playlists, then queues the download.
|
||||||
|
/// Returns the number of items queued, or null if cancelled.
|
||||||
|
Future<int?> showPlaylistDownloadOptionsAndQueue(
|
||||||
|
BuildContext context, {
|
||||||
|
required List<PlexMetadata> items,
|
||||||
|
required PlexClient client,
|
||||||
|
required DownloadProvider downloadProvider,
|
||||||
|
}) async {
|
||||||
|
final selected = await showOptionPickerDialog<DownloadFilter>(
|
||||||
|
context,
|
||||||
|
title: t.downloads.downloadNow,
|
||||||
|
options: [
|
||||||
|
(icon: Symbols.download_rounded, label: t.downloads.allEpisodes, value: DownloadFilter.all),
|
||||||
|
(icon: Symbols.visibility_off_rounded, label: t.downloads.unwatchedOnly, value: DownloadFilter.unwatched),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selected == null || !context.mounted) return null;
|
||||||
|
|
||||||
|
return await downloadProvider.queuePlaylistDownload(
|
||||||
|
items,
|
||||||
|
client,
|
||||||
|
filter: selected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int?> _showEpisodeCountDialog(BuildContext context) {
|
Future<int?> _showEpisodeCountDialog(BuildContext context) {
|
||||||
final autoFocus = InputModeTracker.isKeyboardMode(context);
|
final autoFocus = InputModeTracker.isKeyboardMode(context);
|
||||||
return showDialog<int>(
|
return showDialog<int>(
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
|||||||
// Shuffle
|
// Shuffle
|
||||||
menuActions.add(_MenuAction(value: 'shuffle', icon: Symbols.shuffle_rounded, label: t.mediaMenu.shufflePlay));
|
menuActions.add(_MenuAction(value: 'shuffle', icon: Symbols.shuffle_rounded, label: t.mediaMenu.shufflePlay));
|
||||||
|
|
||||||
|
// Download (video playlists only)
|
||||||
|
if (isPlaylist && (widget.item as PlexPlaylist).playlistType == 'video') {
|
||||||
|
menuActions.add(_MenuAction(value: 'download_playlist', icon: Symbols.download_rounded, label: t.downloads.downloadNow));
|
||||||
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
menuActions.add(_MenuAction(value: 'delete', icon: Symbols.delete_rounded, label: t.common.delete));
|
menuActions.add(_MenuAction(value: 'delete', icon: Symbols.delete_rounded, label: t.common.delete));
|
||||||
|
|
||||||
@@ -534,6 +539,10 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
|||||||
await _handlePlayExternal(context);
|
await _handlePlayExternal(context);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'download_playlist':
|
||||||
|
await _handleDownloadPlaylist(context);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'download':
|
case 'download':
|
||||||
await _handleDownload(context);
|
await _handleDownload(context);
|
||||||
break;
|
break;
|
||||||
@@ -1109,6 +1118,38 @@ class MediaContextMenuState extends State<MediaContextMenu> {
|
|||||||
await ExternalPlayerService.launch(context: context, metadata: metadata, client: client);
|
await ExternalPlayerService.launch(context: context, metadata: metadata, client: client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle download playlist action
|
||||||
|
Future<void> _handleDownloadPlaylist(BuildContext context) async {
|
||||||
|
final playlist = widget.item as PlexPlaylist;
|
||||||
|
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||||
|
final client = _getClientForItem();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final items = await client.getPlaylist(playlist.ratingKey);
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
|
final count = await showPlaylistDownloadOptionsAndQueue(
|
||||||
|
context,
|
||||||
|
items: items,
|
||||||
|
client: client,
|
||||||
|
downloadProvider: downloadProvider,
|
||||||
|
);
|
||||||
|
if (count == null || !context.mounted) return;
|
||||||
|
|
||||||
|
final message = count > 1 ? t.downloads.itemsQueued(count: count) : t.downloads.downloadQueued;
|
||||||
|
showSuccessSnackBar(context, message);
|
||||||
|
} on CellularDownloadBlockedException {
|
||||||
|
if (context.mounted) {
|
||||||
|
showErrorSnackBar(context, t.settings.cellularDownloadBlocked);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
appLogger.e('Failed to queue playlist download', error: e);
|
||||||
|
if (context.mounted) {
|
||||||
|
showErrorSnackBar(context, t.messages.errorLoading(error: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle download action
|
/// Handle download action
|
||||||
Future<void> _handleDownload(BuildContext context) async {
|
Future<void> _handleDownload(BuildContext context) async {
|
||||||
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
final downloadProvider = Provider.of<DownloadProvider>(context, listen: false);
|
||||||
|
|||||||
Reference in New Issue
Block a user