feat: add continue watching details navigation

close #1295
This commit is contained in:
edde746
2026-06-10 12:50:32 +02:00
parent e7efa458e5
commit 3221a0cb1a
44 changed files with 772 additions and 331 deletions
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Мрежа",
"listView": "Списък",
"showHeroSection": "Показвай водеща секция",
"continueWatchingAction": "Действие за продължаване на гледането",
"continueWatchingPlay": "Пусни",
"continueWatchingDetails": "Отвори подробности",
"useGlobalHubs": "Използвай начално оформление",
"useGlobalHubsDescription": "Показвай обединени начални хъбове. В противен случай използвай препоръките на библиотеката.",
"showServerNameOnHubs": "Показвай името на сървъра в хъбовете",
@@ -361,8 +364,8 @@
"markAsWatched": "Маркирай като гледано",
"markAsUnwatched": "Маркирай като негледано",
"removeFromContinueWatching": "Премахни от продължаване на гледането",
"viewDetails": "Виж подробности",
"goToSeries": "Към сериала",
"goToSeason": "Към сезона",
"shufflePlay": "Разбъркано възпроизвеждане",
"shuffleNotAvailableOffline": "Разбърканото възпроизвеждане не е налично офлайн",
"fileInfo": "Информация за файла",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Информацията за файла не е налична",
"errorLoadingFileInfo": "Грешка при зареждане на информация за файла: ${error}",
"errorLoadingSeries": "Грешка при зареждане на сериала",
"errorLoadingSeason": "Грешка при зареждане на сезона",
"musicNotSupported": "Възпроизвеждането на музика все още не се поддържа",
"noDescriptionAvailable": "Няма налично описание",
"noProfilesAvailable": "Няма налични профили",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Gitter",
"listView": "Liste",
"showHeroSection": "Vis hero-sektion",
"continueWatchingAction": "Handling for Fortsæt med at se",
"continueWatchingPlay": "Afspil",
"continueWatchingDetails": "Åbn detaljer",
"useGlobalHubs": "Brug startlayout",
"useGlobalHubsDescription": "Vis samlet startsideindhold. Brug ellers biblioteksanbefalinger.",
"showServerNameOnHubs": "Vis servernavn på hubbe",
@@ -361,8 +364,8 @@
"markAsWatched": "Markér som set",
"markAsUnwatched": "Markér som uset",
"removeFromContinueWatching": "Fjern fra Fortsæt med at se",
"viewDetails": "Vis detaljer",
"goToSeries": "Gå til serie",
"goToSeason": "Gå til sæson",
"shufflePlay": "Afspil tilfældigt",
"shuffleNotAvailableOffline": "Bland afspilning er ikke tilgængelig offline",
"fileInfo": "Filinfo",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Filinfo ikke tilgængelig",
"errorLoadingFileInfo": "Fejl ved indlæsning af filinfo: ${error}",
"errorLoadingSeries": "Fejl ved indlæsning af serie",
"errorLoadingSeason": "Fejl ved indlæsning af sæson",
"musicNotSupported": "Musikafspilning understøttes endnu ikke",
"noDescriptionAvailable": "Ingen beskrivelse tilgængelig",
"noProfilesAvailable": "Ingen profiler tilgængelige",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Raster",
"listView": "Liste",
"showHeroSection": "Hero-Bereich anzeigen",
"continueWatchingAction": "Aktion für Weiterschauen",
"continueWatchingPlay": "Abspielen",
"continueWatchingDetails": "Details öffnen",
"useGlobalHubs": "Startlayout verwenden",
"useGlobalHubsDescription": "Einheitliche Start-Hubs anzeigen. Sonst Bibliotheksempfehlungen verwenden.",
"showServerNameOnHubs": "Servername bei Hubs anzeigen",
@@ -361,8 +364,8 @@
"markAsWatched": "Als gesehen markieren",
"markAsUnwatched": "Als ungesehen markieren",
"removeFromContinueWatching": "Aus Weiterschauen entfernen",
"viewDetails": "Details anzeigen",
"goToSeries": "Zur Serie",
"goToSeason": "Zur Staffel",
"shufflePlay": "Zufallswiedergabe",
"shuffleNotAvailableOffline": "Zufallswiedergabe ist offline nicht verfügbar",
"fileInfo": "Dateiinfo",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Dateiinfo nicht verfügbar",
"errorLoadingFileInfo": "Fehler beim Laden der Dateiinfo: ${error}",
"errorLoadingSeries": "Fehler beim Laden der Serie",
"errorLoadingSeason": "Fehler beim Laden der Staffel",
"musicNotSupported": "Musikwiedergabe wird noch nicht unterstützt",
"noDescriptionAvailable": "Keine Beschreibung verfügbar",
"noProfilesAvailable": "Keine Profile verfügbar",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Grid",
"listView": "List",
"showHeroSection": "Show Hero Section",
"continueWatchingAction": "Continue Watching Action",
"continueWatchingPlay": "Play",
"continueWatchingDetails": "Open Details",
"useGlobalHubs": "Use Home Layout",
"useGlobalHubsDescription": "Show unified home hubs. Otherwise use library recommendations.",
"showServerNameOnHubs": "Show Server Name on Hubs",
@@ -361,8 +364,8 @@
"markAsWatched": "Mark as Watched",
"markAsUnwatched": "Mark as Unwatched",
"removeFromContinueWatching": "Remove from Continue Watching",
"viewDetails": "View details",
"goToSeries": "Go to series",
"goToSeason": "Go to season",
"shufflePlay": "Shuffle Play",
"shuffleNotAvailableOffline": "Shuffle not available offline",
"fileInfo": "File Info",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "File information not available",
"errorLoadingFileInfo": "Error loading file info: ${error}",
"errorLoadingSeries": "Error loading series",
"errorLoadingSeason": "Error loading season",
"musicNotSupported": "Music playback is not yet supported",
"noDescriptionAvailable": "No description available",
"noProfilesAvailable": "No profiles available",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Cuadrícula",
"listView": "Lista",
"showHeroSection": "Mostrar Sección Destacada",
"continueWatchingAction": "Acción de Seguir viendo",
"continueWatchingPlay": "Reproducir",
"continueWatchingDetails": "Abrir detalles",
"useGlobalHubs": "Usar diseño de inicio",
"useGlobalHubsDescription": "Mostrar hubs de inicio unificados. Si no, usar recomendaciones de biblioteca.",
"showServerNameOnHubs": "Mostrar Nombre del Servidor en los Hubs",
@@ -361,8 +364,8 @@
"markAsWatched": "Marcar como Visto",
"markAsUnwatched": "Marcar como No Visto",
"removeFromContinueWatching": "Eliminar de Seguir Viendo",
"viewDetails": "Ver detalles",
"goToSeries": "Ir a la serie",
"goToSeason": "Ir a la temporada",
"shufflePlay": "Reproducción Aleatoria",
"shuffleNotAvailableOffline": "La reproducción aleatoria no está disponible sin conexión",
"fileInfo": "Información del Archivo",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Información de archivo no disponible",
"errorLoadingFileInfo": "Error al cargar info de archivo: ${error}",
"errorLoadingSeries": "Error al cargar la serie",
"errorLoadingSeason": "Error al cargar la temporada",
"musicNotSupported": "La reproducción de música aún no está soportada",
"noDescriptionAvailable": "No hay descripción disponible",
"noProfilesAvailable": "No hay perfiles disponibles",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Grille",
"listView": "Liste",
"showHeroSection": "Afficher la section Hero",
"continueWatchingAction": "Action Continuer à regarder",
"continueWatchingPlay": "Lire",
"continueWatchingDetails": "Ouvrir les détails",
"useGlobalHubs": "Utiliser la mise en page d'accueil",
"useGlobalHubsDescription": "Afficher des hubs d'accueil unifiés. Sinon, utiliser les recommandations de bibliothèque.",
"showServerNameOnHubs": "Afficher le nom du serveur sur les hubs",
@@ -361,8 +364,8 @@
"markAsWatched": "Marquer comme vu",
"markAsUnwatched": "Marquer comme non visionné",
"removeFromContinueWatching": "Supprimer de la liste \"Continuer à regarder\"",
"viewDetails": "Voir les détails",
"goToSeries": "Aller à la série",
"goToSeason": "Aller à la saison",
"shufflePlay": "Lecture aléatoire",
"shuffleNotAvailableOffline": "La lecture aléatoire nest pas disponible hors ligne",
"fileInfo": "Informations sur le fichier",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Informations sur le fichier non disponibles",
"errorLoadingFileInfo": "Erreur lors du chargement des informations sur le fichier: ${error}",
"errorLoadingSeries": "Erreur lors du chargement de la série",
"errorLoadingSeason": "Erreur lors du chargement de la saison",
"musicNotSupported": "La lecture de musique n'est pas encore prise en charge",
"noDescriptionAvailable": "Aucune description disponible",
"noProfilesAvailable": "Aucun profil disponible",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Griglia",
"listView": "Elenco",
"showHeroSection": "Mostra sezione principale",
"continueWatchingAction": "Azione Continua a guardare",
"continueWatchingPlay": "Riproduci",
"continueWatchingDetails": "Apri dettagli",
"useGlobalHubs": "Usa layout home",
"useGlobalHubsDescription": "Mostra hub Home unificati. Altrimenti usa i consigli della libreria.",
"showServerNameOnHubs": "Mostra nome server sugli hub",
@@ -361,8 +364,8 @@
"markAsWatched": "Segna come visto",
"markAsUnwatched": "Segna come non visto",
"removeFromContinueWatching": "Rimuovi da Continua a guardare",
"viewDetails": "Vedi dettagli",
"goToSeries": "Vai alle serie",
"goToSeason": "Vai alla stagione",
"shufflePlay": "Riproduzione casuale",
"shuffleNotAvailableOffline": "Riproduzione casuale non disponibile offline",
"fileInfo": "Info sul file",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Informazioni sul file non disponibili",
"errorLoadingFileInfo": "Errore caricamento informazioni sul file: ${error}",
"errorLoadingSeries": "Errore caricamento serie",
"errorLoadingSeason": "Errore caricamento stagione",
"musicNotSupported": "La riproduzione musicale non è ancora supportata",
"noDescriptionAvailable": "Nessuna descrizione disponibile",
"noProfilesAvailable": "Nessun profilo disponibile",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "グリッド",
"listView": "リスト",
"showHeroSection": "ヒーローセクションを表示",
"continueWatchingAction": "視聴中の操作",
"continueWatchingPlay": "再生",
"continueWatchingDetails": "詳細を開く",
"useGlobalHubs": "ホームレイアウトを使用",
"useGlobalHubsDescription": "統合ホームハブを表示します。オフの場合はライブラリのおすすめを使用します。",
"showServerNameOnHubs": "ハブにサーバー名を表示",
@@ -361,8 +364,8 @@
"markAsWatched": "視聴済みにする",
"markAsUnwatched": "未視聴にする",
"removeFromContinueWatching": "視聴中から削除",
"viewDetails": "詳細を表示",
"goToSeries": "シリーズへ移動",
"goToSeason": "シーズンへ移動",
"shufflePlay": "シャッフル再生",
"shuffleNotAvailableOffline": "オフラインではシャッフルを利用できません",
"fileInfo": "ファイル情報",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "ファイル情報が利用できません",
"errorLoadingFileInfo": "ファイル情報の読み込みエラー: ${error}",
"errorLoadingSeries": "シリーズの読み込みエラー",
"errorLoadingSeason": "シーズンの読み込みエラー",
"musicNotSupported": "音楽の再生はまだサポートされていません",
"noDescriptionAvailable": "説明はありません",
"noProfilesAvailable": "利用可能なプロフィールがありません",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "그리드 보기",
"listView": "목록 보기",
"showHeroSection": "주요 추천 영역 표시",
"continueWatchingAction": "계속 보기 동작",
"continueWatchingPlay": "재생",
"continueWatchingDetails": "상세 정보 열기",
"useGlobalHubs": "홈 레이아웃 사용",
"useGlobalHubsDescription": "통합 홈 허브를 표시합니다. 끄면 라이브러리 추천을 사용합니다.",
"showServerNameOnHubs": "허브에 서버 이름 표시",
@@ -361,8 +364,8 @@
"markAsWatched": "시청 완료로 표시",
"markAsUnwatched": "시청 안 함으로 표시",
"removeFromContinueWatching": "계속 보기에서 제거",
"viewDetails": "상세 정보 보기",
"goToSeries": "시리즈로 이동",
"goToSeason": "시즌으로 이동",
"shufflePlay": "무작위 재생",
"shuffleNotAvailableOffline": "오프라인에서는 셔플을 사용할 수 없습니다",
"fileInfo": "파일 정보",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "파일 정보가 없습니다",
"errorLoadingFileInfo": "파일 정보 로딩 중 오류: ${error}",
"errorLoadingSeries": "시리즈 로딩 중 오류",
"errorLoadingSeason": "시즌 로딩 중 오류",
"musicNotSupported": "음악 재생 미지원",
"noDescriptionAvailable": "설명이 없습니다",
"noProfilesAvailable": "사용 가능한 프로필이 없습니다",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Rutenett",
"listView": "Liste",
"showHeroSection": "Vis fremhevet seksjon",
"continueWatchingAction": "Handling for Fortsett å se",
"continueWatchingPlay": "Spill av",
"continueWatchingDetails": "Åpne detaljer",
"useGlobalHubs": "Bruk startoppsett",
"useGlobalHubsDescription": "Vis samlet startinnhold. Ellers brukes bibliotekanbefalinger.",
"showServerNameOnHubs": "Vis servernavn på huber",
@@ -361,8 +364,8 @@
"markAsWatched": "Merk som sett",
"markAsUnwatched": "Merk som usett",
"removeFromContinueWatching": "Fjern fra Fortsett å se",
"viewDetails": "Vis detaljer",
"goToSeries": "Gå til serie",
"goToSeason": "Gå til sesong",
"shufflePlay": "Tilfeldig avspilling",
"shuffleNotAvailableOffline": "Tilfeldig avspilling er ikke tilgjengelig offline",
"fileInfo": "Filinformasjon",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Filinformasjon ikke tilgjengelig",
"errorLoadingFileInfo": "Feil ved lasting av filinformasjon: ${error}",
"errorLoadingSeries": "Feil ved lasting av serie",
"errorLoadingSeason": "Feil ved lasting av sesong",
"musicNotSupported": "Musikkavspilling støttes ikke ennå",
"noDescriptionAvailable": "Ingen beskrivelse tilgjengelig",
"noProfilesAvailable": "Ingen profiler tilgjengelige",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Raster",
"listView": "Lijst",
"showHeroSection": "Toon hoofdsectie",
"continueWatchingAction": "Actie voor Doorgaan met kijken",
"continueWatchingPlay": "Afspelen",
"continueWatchingDetails": "Details openen",
"useGlobalHubs": "Startlayout gebruiken",
"useGlobalHubsDescription": "Toon gecombineerde home-hubs. Anders bibliotheekaanbevelingen gebruiken.",
"showServerNameOnHubs": "Servernaam tonen bij hubs",
@@ -361,8 +364,8 @@
"markAsWatched": "Markeer als gekeken",
"markAsUnwatched": "Markeer als ongekeken",
"removeFromContinueWatching": "Verwijder uit Doorgaan met kijken",
"viewDetails": "Details bekijken",
"goToSeries": "Ga naar serie",
"goToSeason": "Ga naar seizoen",
"shufflePlay": "Willekeurig afspelen",
"shuffleNotAvailableOffline": "Shuffle is offline niet beschikbaar",
"fileInfo": "Bestand info",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Bestand informatie niet beschikbaar",
"errorLoadingFileInfo": "Fout bij laden bestand info: ${error}",
"errorLoadingSeries": "Fout bij laden serie",
"errorLoadingSeason": "Fout bij laden seizoen",
"musicNotSupported": "Muziek afspelen wordt nog niet ondersteund",
"noDescriptionAvailable": "Geen beschrijving beschikbaar",
"noProfilesAvailable": "Geen profielen beschikbaar",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Siatka",
"listView": "Lista",
"showHeroSection": "Pokaż sekcję wyróżnioną",
"continueWatchingAction": "Akcja Kontynuuj oglądanie",
"continueWatchingPlay": "Odtwórz",
"continueWatchingDetails": "Otwórz szczegóły",
"useGlobalHubs": "Użyj układu strony głównej",
"useGlobalHubsDescription": "Pokaż ujednolicone huby ekranu głównego. W przeciwnym razie użyj rekomendacji bibliotek.",
"showServerNameOnHubs": "Pokaż nazwę serwera w hubach",
@@ -361,8 +364,8 @@
"markAsWatched": "Oznacz jako obejrzane",
"markAsUnwatched": "Oznacz jako nieobejrzane",
"removeFromContinueWatching": "Usuń z kontynuowania oglądania",
"viewDetails": "Pokaż szczegóły",
"goToSeries": "Przejdź do serialu",
"goToSeason": "Przejdź do sezonu",
"shufflePlay": "Odtwarzanie losowe",
"shuffleNotAvailableOffline": "Odtwarzanie losowe nie jest dostępne offline",
"fileInfo": "Informacje o pliku",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Informacje o pliku niedostępne",
"errorLoadingFileInfo": "Błąd ładowania informacji o pliku: ${error}",
"errorLoadingSeries": "Błąd ładowania serialu",
"errorLoadingSeason": "Błąd ładowania sezonu",
"musicNotSupported": "Odtwarzanie muzyki nie jest jeszcze obsługiwane",
"noDescriptionAvailable": "Brak dostępnego opisu",
"noProfilesAvailable": "Brak dostępnych profili",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Grade",
"listView": "Lista",
"showHeroSection": "Mostrar Seção de Destaque",
"continueWatchingAction": "Ação de Continuar Assistindo",
"continueWatchingPlay": "Reproduzir",
"continueWatchingDetails": "Abrir detalhes",
"useGlobalHubs": "Usar layout inicial",
"useGlobalHubsDescription": "Mostrar hubs iniciais unificados. Caso contrário, usar recomendações da biblioteca.",
"showServerNameOnHubs": "Mostrar Nome do Servidor nos Hubs",
@@ -361,8 +364,8 @@
"markAsWatched": "Marcar como Assistido",
"markAsUnwatched": "Marcar como Não Assistido",
"removeFromContinueWatching": "Remover de Continuar Assistindo",
"viewDetails": "Ver detalhes",
"goToSeries": "Ir para a série",
"goToSeason": "Ir para a temporada",
"shufflePlay": "Reprodução Aleatória",
"shuffleNotAvailableOffline": "Reprodução aleatória indisponível offline",
"fileInfo": "Info do Arquivo",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Informações do arquivo não disponíveis",
"errorLoadingFileInfo": "Erro ao carregar info do arquivo: ${error}",
"errorLoadingSeries": "Erro ao carregar série",
"errorLoadingSeason": "Erro ao carregar temporada",
"musicNotSupported": "Reprodução de música ainda não é suportada",
"noDescriptionAvailable": "Nenhuma descrição disponível",
"noProfilesAvailable": "Nenhum perfil disponível",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Сетка",
"listView": "Список",
"showHeroSection": "Показать раздел избранного",
"continueWatchingAction": "Действие для «Продолжить просмотр»",
"continueWatchingPlay": "Воспроизвести",
"continueWatchingDetails": "Открыть сведения",
"useGlobalHubs": "Использовать макет главной",
"useGlobalHubsDescription": "Показывать единые разделы главной. Иначе использовать рекомендации библиотек.",
"showServerNameOnHubs": "Показывать имя сервера в хабах",
@@ -361,8 +364,8 @@
"markAsWatched": "Отметить как просмотренное",
"markAsUnwatched": "Отметить как непросмотренное",
"removeFromContinueWatching": "Удалить из «Продолжить просмотр»",
"viewDetails": "Показать сведения",
"goToSeries": "Перейти к сериалу",
"goToSeason": "Перейти к сезону",
"shufflePlay": "Случайное воспроизведение",
"shuffleNotAvailableOffline": "Перемешивание недоступно офлайн",
"fileInfo": "Информация о файле",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Информация о файле недоступна",
"errorLoadingFileInfo": "Ошибка загрузки информации о файле: ${error}",
"errorLoadingSeries": "Ошибка загрузки сериала",
"errorLoadingSeason": "Ошибка загрузки сезона",
"musicNotSupported": "Воспроизведение музыки пока не поддерживается",
"noDescriptionAvailable": "Описание недоступно",
"noProfilesAvailable": "Профили недоступны",
+1 -1
View File
@@ -4,7 +4,7 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 16
/// Strings: 20352 (1272 per locale)
/// Strings: 20384 (1274 per locale)
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsBg extends TranslationsSettingsEn {
@override String get gridView => 'Мрежа';
@override String get listView => 'Списък';
@override String get showHeroSection => 'Показвай водеща секция';
@override String get continueWatchingAction => 'Действие за продължаване на гледането';
@override String get continueWatchingPlay => 'Пусни';
@override String get continueWatchingDetails => 'Отвори подробности';
@override String get useGlobalHubs => 'Използвай начално оформление';
@override String get useGlobalHubsDescription => 'Показвай обединени начални хъбове. В противен случай използвай препоръките на библиотеката.';
@override String get showServerNameOnHubs => 'Показвай името на сървъра в хъбовете';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuBg extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Маркирай като гледано';
@override String get markAsUnwatched => 'Маркирай като негледано';
@override String get removeFromContinueWatching => 'Премахни от продължаване на гледането';
@override String get viewDetails => 'Виж подробности';
@override String get goToSeries => 'Към сериала';
@override String get goToSeason => 'Към сезона';
@override String get shufflePlay => 'Разбъркано възпроизвеждане';
@override String get shuffleNotAvailableOffline => 'Разбърканото възпроизвеждане не е налично офлайн';
@override String get fileInfo => 'Информация за файла';
@@ -673,7 +676,6 @@ class _TranslationsMessagesBg extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Информацията за файла не е налична';
@override String errorLoadingFileInfo({required Object error}) => 'Грешка при зареждане на информация за файла: ${error}';
@override String get errorLoadingSeries => 'Грешка при зареждане на сериала';
@override String get errorLoadingSeason => 'Грешка при зареждане на сезона';
@override String get musicNotSupported => 'Възпроизвеждането на музика все още не се поддържа';
@override String get noDescriptionAvailable => 'Няма налично описание';
@override String get noProfilesAvailable => 'Няма налични профили';
@@ -2027,6 +2029,9 @@ extension on TranslationsBg {
'settings.gridView' => 'Мрежа',
'settings.listView' => 'Списък',
'settings.showHeroSection' => 'Показвай водеща секция',
'settings.continueWatchingAction' => 'Действие за продължаване на гледането',
'settings.continueWatchingPlay' => 'Пусни',
'settings.continueWatchingDetails' => 'Отвори подробности',
'settings.useGlobalHubs' => 'Използвай начално оформление',
'settings.useGlobalHubsDescription' => 'Показвай обединени начални хъбове. В противен случай използвай препоръките на библиотеката.',
'settings.showServerNameOnHubs' => 'Показвай името на сървъра в хъбовете',
@@ -2262,8 +2267,8 @@ extension on TranslationsBg {
'mediaMenu.markAsWatched' => 'Маркирай като гледано',
'mediaMenu.markAsUnwatched' => 'Маркирай като негледано',
'mediaMenu.removeFromContinueWatching' => 'Премахни от продължаване на гледането',
'mediaMenu.viewDetails' => 'Виж подробности',
'mediaMenu.goToSeries' => 'Към сериала',
'mediaMenu.goToSeason' => 'Към сезона',
'mediaMenu.shufflePlay' => 'Разбъркано възпроизвеждане',
'mediaMenu.shuffleNotAvailableOffline' => 'Разбърканото възпроизвеждане не е налично офлайн',
'mediaMenu.fileInfo' => 'Информация за файла',
@@ -2395,7 +2400,6 @@ extension on TranslationsBg {
'messages.fileInfoNotAvailable' => 'Информацията за файла не е налична',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Грешка при зареждане на информация за файла: ${error}',
'messages.errorLoadingSeries' => 'Грешка при зареждане на сериала',
'messages.errorLoadingSeason' => 'Грешка при зареждане на сезона',
'messages.musicNotSupported' => 'Възпроизвеждането на музика все още не се поддържа',
'messages.noDescriptionAvailable' => 'Няма налично описание',
'messages.noProfilesAvailable' => 'Няма налични профили',
@@ -2431,10 +2435,10 @@ extension on TranslationsBg {
'subtitlingStyling.border' => 'Рамка',
'subtitlingStyling.background' => 'Фон',
'subtitlingStyling.fontSize' => 'Размер на шрифта',
'subtitlingStyling.textColor' => 'Цвят на текста',
'subtitlingStyling.borderSize' => 'Размер на рамката',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Цвят на текста',
'subtitlingStyling.borderSize' => 'Размер на рамката',
'subtitlingStyling.borderColor' => 'Цвят на рамката',
'subtitlingStyling.backgroundOpacity' => 'Прозрачност на фона',
'subtitlingStyling.backgroundColor' => 'Цвят на фона',
@@ -2945,10 +2949,10 @@ extension on TranslationsBg {
'companionRemote.remote.menu' => 'Меню',
'companionRemote.remote.tabNavigation' => 'Навигация с Tab',
'companionRemote.remote.tabDiscover' => 'Открий',
'companionRemote.remote.tabLibraries' => 'Библиотеки',
'companionRemote.remote.tabSearch' => 'Търсене',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Библиотеки',
'companionRemote.remote.tabSearch' => 'Търсене',
'companionRemote.remote.tabDownloads' => 'Изтегляния',
'companionRemote.remote.tabSettings' => 'Настройки',
'companionRemote.remote.previous' => 'Предишен',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsDa extends TranslationsSettingsEn {
@override String get gridView => 'Gitter';
@override String get listView => 'Liste';
@override String get showHeroSection => 'Vis hero-sektion';
@override String get continueWatchingAction => 'Handling for Fortsæt med at se';
@override String get continueWatchingPlay => 'Afspil';
@override String get continueWatchingDetails => 'Åbn detaljer';
@override String get useGlobalHubs => 'Brug startlayout';
@override String get useGlobalHubsDescription => 'Vis samlet startsideindhold. Brug ellers biblioteksanbefalinger.';
@override String get showServerNameOnHubs => 'Vis servernavn på hubbe';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuDa extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Markér som set';
@override String get markAsUnwatched => 'Markér som uset';
@override String get removeFromContinueWatching => 'Fjern fra Fortsæt med at se';
@override String get viewDetails => 'Vis detaljer';
@override String get goToSeries => 'Gå til serie';
@override String get goToSeason => 'Gå til sæson';
@override String get shufflePlay => 'Afspil tilfældigt';
@override String get shuffleNotAvailableOffline => 'Bland afspilning er ikke tilgængelig offline';
@override String get fileInfo => 'Filinfo';
@@ -673,7 +676,6 @@ class _TranslationsMessagesDa extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Filinfo ikke tilgængelig';
@override String errorLoadingFileInfo({required Object error}) => 'Fejl ved indlæsning af filinfo: ${error}';
@override String get errorLoadingSeries => 'Fejl ved indlæsning af serie';
@override String get errorLoadingSeason => 'Fejl ved indlæsning af sæson';
@override String get musicNotSupported => 'Musikafspilning understøttes endnu ikke';
@override String get noDescriptionAvailable => 'Ingen beskrivelse tilgængelig';
@override String get noProfilesAvailable => 'Ingen profiler tilgængelige';
@@ -2027,6 +2029,9 @@ extension on TranslationsDa {
'settings.gridView' => 'Gitter',
'settings.listView' => 'Liste',
'settings.showHeroSection' => 'Vis hero-sektion',
'settings.continueWatchingAction' => 'Handling for Fortsæt med at se',
'settings.continueWatchingPlay' => 'Afspil',
'settings.continueWatchingDetails' => 'Åbn detaljer',
'settings.useGlobalHubs' => 'Brug startlayout',
'settings.useGlobalHubsDescription' => 'Vis samlet startsideindhold. Brug ellers biblioteksanbefalinger.',
'settings.showServerNameOnHubs' => 'Vis servernavn på hubbe',
@@ -2262,8 +2267,8 @@ extension on TranslationsDa {
'mediaMenu.markAsWatched' => 'Markér som set',
'mediaMenu.markAsUnwatched' => 'Markér som uset',
'mediaMenu.removeFromContinueWatching' => 'Fjern fra Fortsæt med at se',
'mediaMenu.viewDetails' => 'Vis detaljer',
'mediaMenu.goToSeries' => 'Gå til serie',
'mediaMenu.goToSeason' => 'Gå til sæson',
'mediaMenu.shufflePlay' => 'Afspil tilfældigt',
'mediaMenu.shuffleNotAvailableOffline' => 'Bland afspilning er ikke tilgængelig offline',
'mediaMenu.fileInfo' => 'Filinfo',
@@ -2395,7 +2400,6 @@ extension on TranslationsDa {
'messages.fileInfoNotAvailable' => 'Filinfo ikke tilgængelig',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Fejl ved indlæsning af filinfo: ${error}',
'messages.errorLoadingSeries' => 'Fejl ved indlæsning af serie',
'messages.errorLoadingSeason' => 'Fejl ved indlæsning af sæson',
'messages.musicNotSupported' => 'Musikafspilning understøttes endnu ikke',
'messages.noDescriptionAvailable' => 'Ingen beskrivelse tilgængelig',
'messages.noProfilesAvailable' => 'Ingen profiler tilgængelige',
@@ -2431,10 +2435,10 @@ extension on TranslationsDa {
'subtitlingStyling.border' => 'Kant',
'subtitlingStyling.background' => 'Baggrund',
'subtitlingStyling.fontSize' => 'Skriftstørrelse',
'subtitlingStyling.textColor' => 'Tekstfarve',
'subtitlingStyling.borderSize' => 'Kantstørrelse',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Tekstfarve',
'subtitlingStyling.borderSize' => 'Kantstørrelse',
'subtitlingStyling.borderColor' => 'Kantfarve',
'subtitlingStyling.backgroundOpacity' => 'Baggrundsgennemsigtighed',
'subtitlingStyling.backgroundColor' => 'Baggrundsfarve',
@@ -2945,10 +2949,10 @@ extension on TranslationsDa {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Fanenavigation',
'companionRemote.remote.tabDiscover' => 'Opdag',
'companionRemote.remote.tabLibraries' => 'Biblioteker',
'companionRemote.remote.tabSearch' => 'Søg',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Biblioteker',
'companionRemote.remote.tabSearch' => 'Søg',
'companionRemote.remote.tabDownloads' => 'Downloads',
'companionRemote.remote.tabSettings' => 'Indstillinger',
'companionRemote.remote.previous' => 'Forrige',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsDe extends TranslationsSettingsEn {
@override String get gridView => 'Raster';
@override String get listView => 'Liste';
@override String get showHeroSection => 'Hero-Bereich anzeigen';
@override String get continueWatchingAction => 'Aktion für Weiterschauen';
@override String get continueWatchingPlay => 'Abspielen';
@override String get continueWatchingDetails => 'Details öffnen';
@override String get useGlobalHubs => 'Startlayout verwenden';
@override String get useGlobalHubsDescription => 'Einheitliche Start-Hubs anzeigen. Sonst Bibliotheksempfehlungen verwenden.';
@override String get showServerNameOnHubs => 'Servername bei Hubs anzeigen';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuDe extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Als gesehen markieren';
@override String get markAsUnwatched => 'Als ungesehen markieren';
@override String get removeFromContinueWatching => 'Aus Weiterschauen entfernen';
@override String get viewDetails => 'Details anzeigen';
@override String get goToSeries => 'Zur Serie';
@override String get goToSeason => 'Zur Staffel';
@override String get shufflePlay => 'Zufallswiedergabe';
@override String get shuffleNotAvailableOffline => 'Zufallswiedergabe ist offline nicht verfügbar';
@override String get fileInfo => 'Dateiinfo';
@@ -673,7 +676,6 @@ class _TranslationsMessagesDe extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Dateiinfo nicht verfügbar';
@override String errorLoadingFileInfo({required Object error}) => 'Fehler beim Laden der Dateiinfo: ${error}';
@override String get errorLoadingSeries => 'Fehler beim Laden der Serie';
@override String get errorLoadingSeason => 'Fehler beim Laden der Staffel';
@override String get musicNotSupported => 'Musikwiedergabe wird noch nicht unterstützt';
@override String get noDescriptionAvailable => 'Keine Beschreibung verfügbar';
@override String get noProfilesAvailable => 'Keine Profile verfügbar';
@@ -2027,6 +2029,9 @@ extension on TranslationsDe {
'settings.gridView' => 'Raster',
'settings.listView' => 'Liste',
'settings.showHeroSection' => 'Hero-Bereich anzeigen',
'settings.continueWatchingAction' => 'Aktion für Weiterschauen',
'settings.continueWatchingPlay' => 'Abspielen',
'settings.continueWatchingDetails' => 'Details öffnen',
'settings.useGlobalHubs' => 'Startlayout verwenden',
'settings.useGlobalHubsDescription' => 'Einheitliche Start-Hubs anzeigen. Sonst Bibliotheksempfehlungen verwenden.',
'settings.showServerNameOnHubs' => 'Servername bei Hubs anzeigen',
@@ -2262,8 +2267,8 @@ extension on TranslationsDe {
'mediaMenu.markAsWatched' => 'Als gesehen markieren',
'mediaMenu.markAsUnwatched' => 'Als ungesehen markieren',
'mediaMenu.removeFromContinueWatching' => 'Aus Weiterschauen entfernen',
'mediaMenu.viewDetails' => 'Details anzeigen',
'mediaMenu.goToSeries' => 'Zur Serie',
'mediaMenu.goToSeason' => 'Zur Staffel',
'mediaMenu.shufflePlay' => 'Zufallswiedergabe',
'mediaMenu.shuffleNotAvailableOffline' => 'Zufallswiedergabe ist offline nicht verfügbar',
'mediaMenu.fileInfo' => 'Dateiinfo',
@@ -2395,7 +2400,6 @@ extension on TranslationsDe {
'messages.fileInfoNotAvailable' => 'Dateiinfo nicht verfügbar',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Fehler beim Laden der Dateiinfo: ${error}',
'messages.errorLoadingSeries' => 'Fehler beim Laden der Serie',
'messages.errorLoadingSeason' => 'Fehler beim Laden der Staffel',
'messages.musicNotSupported' => 'Musikwiedergabe wird noch nicht unterstützt',
'messages.noDescriptionAvailable' => 'Keine Beschreibung verfügbar',
'messages.noProfilesAvailable' => 'Keine Profile verfügbar',
@@ -2431,10 +2435,10 @@ extension on TranslationsDe {
'subtitlingStyling.border' => 'Rahmen',
'subtitlingStyling.background' => 'Hintergrund',
'subtitlingStyling.fontSize' => 'Schriftgröße',
'subtitlingStyling.textColor' => 'Textfarbe',
'subtitlingStyling.borderSize' => 'Rahmengröße',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Textfarbe',
'subtitlingStyling.borderSize' => 'Rahmengröße',
'subtitlingStyling.borderColor' => 'Rahmenfarbe',
'subtitlingStyling.backgroundOpacity' => 'Hintergrunddeckkraft',
'subtitlingStyling.backgroundColor' => 'Hintergrundfarbe',
@@ -2945,10 +2949,10 @@ extension on TranslationsDe {
'companionRemote.remote.menu' => 'Menü',
'companionRemote.remote.tabNavigation' => 'Tab-Navigation',
'companionRemote.remote.tabDiscover' => 'Entdecken',
'companionRemote.remote.tabLibraries' => 'Mediatheken',
'companionRemote.remote.tabSearch' => 'Suche',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Mediatheken',
'companionRemote.remote.tabSearch' => 'Suche',
'companionRemote.remote.tabDownloads' => 'Downloads',
'companionRemote.remote.tabSettings' => 'Einstellungen',
'companionRemote.remote.previous' => 'Zurück',
+20 -12
View File
@@ -459,6 +459,15 @@ class TranslationsSettingsEn {
/// en: 'Show Hero Section'
String get showHeroSection => 'Show Hero Section';
/// en: 'Continue Watching Action'
String get continueWatchingAction => 'Continue Watching Action';
/// en: 'Play'
String get continueWatchingPlay => 'Play';
/// en: 'Open Details'
String get continueWatchingDetails => 'Open Details';
/// en: 'Use Home Layout'
String get useGlobalHubs => 'Use Home Layout';
@@ -1127,12 +1136,12 @@ class TranslationsMediaMenuEn {
/// en: 'Remove from Continue Watching'
String get removeFromContinueWatching => 'Remove from Continue Watching';
/// en: 'View details'
String get viewDetails => 'View details';
/// en: 'Go to series'
String get goToSeries => 'Go to series';
/// en: 'Go to season'
String get goToSeason => 'Go to season';
/// en: 'Shuffle Play'
String get shufflePlay => 'Shuffle Play';
@@ -1561,9 +1570,6 @@ class TranslationsMessagesEn {
/// en: 'Error loading series'
String get errorLoadingSeries => 'Error loading series';
/// en: 'Error loading season'
String get errorLoadingSeason => 'Error loading season';
/// en: 'Music playback is not yet supported'
String get musicNotSupported => 'Music playback is not yet supported';
@@ -4577,6 +4583,9 @@ extension on Translations {
'settings.gridView' => 'Grid',
'settings.listView' => 'List',
'settings.showHeroSection' => 'Show Hero Section',
'settings.continueWatchingAction' => 'Continue Watching Action',
'settings.continueWatchingPlay' => 'Play',
'settings.continueWatchingDetails' => 'Open Details',
'settings.useGlobalHubs' => 'Use Home Layout',
'settings.useGlobalHubsDescription' => 'Show unified home hubs. Otherwise use library recommendations.',
'settings.showServerNameOnHubs' => 'Show Server Name on Hubs',
@@ -4812,8 +4821,8 @@ extension on Translations {
'mediaMenu.markAsWatched' => 'Mark as Watched',
'mediaMenu.markAsUnwatched' => 'Mark as Unwatched',
'mediaMenu.removeFromContinueWatching' => 'Remove from Continue Watching',
'mediaMenu.viewDetails' => 'View details',
'mediaMenu.goToSeries' => 'Go to series',
'mediaMenu.goToSeason' => 'Go to season',
'mediaMenu.shufflePlay' => 'Shuffle Play',
'mediaMenu.shuffleNotAvailableOffline' => 'Shuffle not available offline',
'mediaMenu.fileInfo' => 'File Info',
@@ -4945,7 +4954,6 @@ extension on Translations {
'messages.fileInfoNotAvailable' => 'File information not available',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Error loading file info: ${error}',
'messages.errorLoadingSeries' => 'Error loading series',
'messages.errorLoadingSeason' => 'Error loading season',
'messages.musicNotSupported' => 'Music playback is not yet supported',
'messages.noDescriptionAvailable' => 'No description available',
'messages.noProfilesAvailable' => 'No profiles available',
@@ -4981,10 +4989,10 @@ extension on Translations {
'subtitlingStyling.border' => 'Border',
'subtitlingStyling.background' => 'Background',
'subtitlingStyling.fontSize' => 'Font Size',
'subtitlingStyling.textColor' => 'Text Color',
'subtitlingStyling.borderSize' => 'Border Size',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Text Color',
'subtitlingStyling.borderSize' => 'Border Size',
'subtitlingStyling.borderColor' => 'Border Color',
'subtitlingStyling.backgroundOpacity' => 'Background Opacity',
'subtitlingStyling.backgroundColor' => 'Background Color',
@@ -5495,10 +5503,10 @@ extension on Translations {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Tab Navigation',
'companionRemote.remote.tabDiscover' => 'Discover',
'companionRemote.remote.tabLibraries' => 'Libraries',
'companionRemote.remote.tabSearch' => 'Search',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Libraries',
'companionRemote.remote.tabSearch' => 'Search',
'companionRemote.remote.tabDownloads' => 'Downloads',
'companionRemote.remote.tabSettings' => 'Settings',
'companionRemote.remote.previous' => 'Previous',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsEs extends TranslationsSettingsEn {
@override String get gridView => 'Cuadrícula';
@override String get listView => 'Lista';
@override String get showHeroSection => 'Mostrar Sección Destacada';
@override String get continueWatchingAction => 'Acción de Seguir viendo';
@override String get continueWatchingPlay => 'Reproducir';
@override String get continueWatchingDetails => 'Abrir detalles';
@override String get useGlobalHubs => 'Usar diseño de inicio';
@override String get useGlobalHubsDescription => 'Mostrar hubs de inicio unificados. Si no, usar recomendaciones de biblioteca.';
@override String get showServerNameOnHubs => 'Mostrar Nombre del Servidor en los Hubs';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuEs extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Marcar como Visto';
@override String get markAsUnwatched => 'Marcar como No Visto';
@override String get removeFromContinueWatching => 'Eliminar de Seguir Viendo';
@override String get viewDetails => 'Ver detalles';
@override String get goToSeries => 'Ir a la serie';
@override String get goToSeason => 'Ir a la temporada';
@override String get shufflePlay => 'Reproducción Aleatoria';
@override String get shuffleNotAvailableOffline => 'La reproducción aleatoria no está disponible sin conexión';
@override String get fileInfo => 'Información del Archivo';
@@ -673,7 +676,6 @@ class _TranslationsMessagesEs extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Información de archivo no disponible';
@override String errorLoadingFileInfo({required Object error}) => 'Error al cargar info de archivo: ${error}';
@override String get errorLoadingSeries => 'Error al cargar la serie';
@override String get errorLoadingSeason => 'Error al cargar la temporada';
@override String get musicNotSupported => 'La reproducción de música aún no está soportada';
@override String get noDescriptionAvailable => 'No hay descripción disponible';
@override String get noProfilesAvailable => 'No hay perfiles disponibles';
@@ -2027,6 +2029,9 @@ extension on TranslationsEs {
'settings.gridView' => 'Cuadrícula',
'settings.listView' => 'Lista',
'settings.showHeroSection' => 'Mostrar Sección Destacada',
'settings.continueWatchingAction' => 'Acción de Seguir viendo',
'settings.continueWatchingPlay' => 'Reproducir',
'settings.continueWatchingDetails' => 'Abrir detalles',
'settings.useGlobalHubs' => 'Usar diseño de inicio',
'settings.useGlobalHubsDescription' => 'Mostrar hubs de inicio unificados. Si no, usar recomendaciones de biblioteca.',
'settings.showServerNameOnHubs' => 'Mostrar Nombre del Servidor en los Hubs',
@@ -2262,8 +2267,8 @@ extension on TranslationsEs {
'mediaMenu.markAsWatched' => 'Marcar como Visto',
'mediaMenu.markAsUnwatched' => 'Marcar como No Visto',
'mediaMenu.removeFromContinueWatching' => 'Eliminar de Seguir Viendo',
'mediaMenu.viewDetails' => 'Ver detalles',
'mediaMenu.goToSeries' => 'Ir a la serie',
'mediaMenu.goToSeason' => 'Ir a la temporada',
'mediaMenu.shufflePlay' => 'Reproducción Aleatoria',
'mediaMenu.shuffleNotAvailableOffline' => 'La reproducción aleatoria no está disponible sin conexión',
'mediaMenu.fileInfo' => 'Información del Archivo',
@@ -2395,7 +2400,6 @@ extension on TranslationsEs {
'messages.fileInfoNotAvailable' => 'Información de archivo no disponible',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Error al cargar info de archivo: ${error}',
'messages.errorLoadingSeries' => 'Error al cargar la serie',
'messages.errorLoadingSeason' => 'Error al cargar la temporada',
'messages.musicNotSupported' => 'La reproducción de música aún no está soportada',
'messages.noDescriptionAvailable' => 'No hay descripción disponible',
'messages.noProfilesAvailable' => 'No hay perfiles disponibles',
@@ -2431,10 +2435,10 @@ extension on TranslationsEs {
'subtitlingStyling.border' => 'Borde',
'subtitlingStyling.background' => 'Fondo',
'subtitlingStyling.fontSize' => 'Tamaño de Fuente',
'subtitlingStyling.textColor' => 'Color de Texto',
'subtitlingStyling.borderSize' => 'Tamaño de Borde',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Color de Texto',
'subtitlingStyling.borderSize' => 'Tamaño de Borde',
'subtitlingStyling.borderColor' => 'Color de Borde',
'subtitlingStyling.backgroundOpacity' => 'Opacidad de Fondo',
'subtitlingStyling.backgroundColor' => 'Color de Fondo',
@@ -2945,10 +2949,10 @@ extension on TranslationsEs {
'companionRemote.remote.menu' => 'Menú',
'companionRemote.remote.tabNavigation' => 'Navegación por pestañas',
'companionRemote.remote.tabDiscover' => 'Descubrir',
'companionRemote.remote.tabLibraries' => 'Bibliotecas',
'companionRemote.remote.tabSearch' => 'Buscar',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Bibliotecas',
'companionRemote.remote.tabSearch' => 'Buscar',
'companionRemote.remote.tabDownloads' => 'Descargas',
'companionRemote.remote.tabSettings' => 'Configuración',
'companionRemote.remote.previous' => 'Anterior',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsFr extends TranslationsSettingsEn {
@override String get gridView => 'Grille';
@override String get listView => 'Liste';
@override String get showHeroSection => 'Afficher la section Hero';
@override String get continueWatchingAction => 'Action Continuer à regarder';
@override String get continueWatchingPlay => 'Lire';
@override String get continueWatchingDetails => 'Ouvrir les détails';
@override String get useGlobalHubs => 'Utiliser la mise en page d\'accueil';
@override String get useGlobalHubsDescription => 'Afficher des hubs d\'accueil unifiés. Sinon, utiliser les recommandations de bibliothèque.';
@override String get showServerNameOnHubs => 'Afficher le nom du serveur sur les hubs';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuFr extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Marquer comme vu';
@override String get markAsUnwatched => 'Marquer comme non visionné';
@override String get removeFromContinueWatching => 'Supprimer de la liste "Continuer à regarder"';
@override String get viewDetails => 'Voir les détails';
@override String get goToSeries => 'Aller à la série';
@override String get goToSeason => 'Aller à la saison';
@override String get shufflePlay => 'Lecture aléatoire';
@override String get shuffleNotAvailableOffline => 'La lecture aléatoire nest pas disponible hors ligne';
@override String get fileInfo => 'Informations sur le fichier';
@@ -673,7 +676,6 @@ class _TranslationsMessagesFr extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Informations sur le fichier non disponibles';
@override String errorLoadingFileInfo({required Object error}) => 'Erreur lors du chargement des informations sur le fichier: ${error}';
@override String get errorLoadingSeries => 'Erreur lors du chargement de la série';
@override String get errorLoadingSeason => 'Erreur lors du chargement de la saison';
@override String get musicNotSupported => 'La lecture de musique n\'est pas encore prise en charge';
@override String get noDescriptionAvailable => 'Aucune description disponible';
@override String get noProfilesAvailable => 'Aucun profil disponible';
@@ -2027,6 +2029,9 @@ extension on TranslationsFr {
'settings.gridView' => 'Grille',
'settings.listView' => 'Liste',
'settings.showHeroSection' => 'Afficher la section Hero',
'settings.continueWatchingAction' => 'Action Continuer à regarder',
'settings.continueWatchingPlay' => 'Lire',
'settings.continueWatchingDetails' => 'Ouvrir les détails',
'settings.useGlobalHubs' => 'Utiliser la mise en page d\'accueil',
'settings.useGlobalHubsDescription' => 'Afficher des hubs d\'accueil unifiés. Sinon, utiliser les recommandations de bibliothèque.',
'settings.showServerNameOnHubs' => 'Afficher le nom du serveur sur les hubs',
@@ -2262,8 +2267,8 @@ extension on TranslationsFr {
'mediaMenu.markAsWatched' => 'Marquer comme vu',
'mediaMenu.markAsUnwatched' => 'Marquer comme non visionné',
'mediaMenu.removeFromContinueWatching' => 'Supprimer de la liste "Continuer à regarder"',
'mediaMenu.viewDetails' => 'Voir les détails',
'mediaMenu.goToSeries' => 'Aller à la série',
'mediaMenu.goToSeason' => 'Aller à la saison',
'mediaMenu.shufflePlay' => 'Lecture aléatoire',
'mediaMenu.shuffleNotAvailableOffline' => 'La lecture aléatoire nest pas disponible hors ligne',
'mediaMenu.fileInfo' => 'Informations sur le fichier',
@@ -2395,7 +2400,6 @@ extension on TranslationsFr {
'messages.fileInfoNotAvailable' => 'Informations sur le fichier non disponibles',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Erreur lors du chargement des informations sur le fichier: ${error}',
'messages.errorLoadingSeries' => 'Erreur lors du chargement de la série',
'messages.errorLoadingSeason' => 'Erreur lors du chargement de la saison',
'messages.musicNotSupported' => 'La lecture de musique n\'est pas encore prise en charge',
'messages.noDescriptionAvailable' => 'Aucune description disponible',
'messages.noProfilesAvailable' => 'Aucun profil disponible',
@@ -2431,10 +2435,10 @@ extension on TranslationsFr {
'subtitlingStyling.border' => 'Bordure',
'subtitlingStyling.background' => 'Arrière-plan',
'subtitlingStyling.fontSize' => 'Taille de la police',
'subtitlingStyling.textColor' => 'Couleur du texte',
'subtitlingStyling.borderSize' => 'Taille de la bordure',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Couleur du texte',
'subtitlingStyling.borderSize' => 'Taille de la bordure',
'subtitlingStyling.borderColor' => 'Couleur de la bordure',
'subtitlingStyling.backgroundOpacity' => 'Opacité d\'arrière-plan',
'subtitlingStyling.backgroundColor' => 'Couleur d\'arrière-plan',
@@ -2945,10 +2949,10 @@ extension on TranslationsFr {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Navigation par onglets',
'companionRemote.remote.tabDiscover' => 'Découvrir',
'companionRemote.remote.tabLibraries' => 'Bibliothèques',
'companionRemote.remote.tabSearch' => 'Rechercher',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Bibliothèques',
'companionRemote.remote.tabSearch' => 'Rechercher',
'companionRemote.remote.tabDownloads' => 'Téléchargements',
'companionRemote.remote.tabSettings' => 'Paramètres',
'companionRemote.remote.previous' => 'Précédent',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsIt extends TranslationsSettingsEn {
@override String get gridView => 'Griglia';
@override String get listView => 'Elenco';
@override String get showHeroSection => 'Mostra sezione principale';
@override String get continueWatchingAction => 'Azione Continua a guardare';
@override String get continueWatchingPlay => 'Riproduci';
@override String get continueWatchingDetails => 'Apri dettagli';
@override String get useGlobalHubs => 'Usa layout home';
@override String get useGlobalHubsDescription => 'Mostra hub Home unificati. Altrimenti usa i consigli della libreria.';
@override String get showServerNameOnHubs => 'Mostra nome server sugli hub';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuIt extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Segna come visto';
@override String get markAsUnwatched => 'Segna come non visto';
@override String get removeFromContinueWatching => 'Rimuovi da Continua a guardare';
@override String get viewDetails => 'Vedi dettagli';
@override String get goToSeries => 'Vai alle serie';
@override String get goToSeason => 'Vai alla stagione';
@override String get shufflePlay => 'Riproduzione casuale';
@override String get shuffleNotAvailableOffline => 'Riproduzione casuale non disponibile offline';
@override String get fileInfo => 'Info sul file';
@@ -673,7 +676,6 @@ class _TranslationsMessagesIt extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Informazioni sul file non disponibili';
@override String errorLoadingFileInfo({required Object error}) => 'Errore caricamento informazioni sul file: ${error}';
@override String get errorLoadingSeries => 'Errore caricamento serie';
@override String get errorLoadingSeason => 'Errore caricamento stagione';
@override String get musicNotSupported => 'La riproduzione musicale non è ancora supportata';
@override String get noDescriptionAvailable => 'Nessuna descrizione disponibile';
@override String get noProfilesAvailable => 'Nessun profilo disponibile';
@@ -2027,6 +2029,9 @@ extension on TranslationsIt {
'settings.gridView' => 'Griglia',
'settings.listView' => 'Elenco',
'settings.showHeroSection' => 'Mostra sezione principale',
'settings.continueWatchingAction' => 'Azione Continua a guardare',
'settings.continueWatchingPlay' => 'Riproduci',
'settings.continueWatchingDetails' => 'Apri dettagli',
'settings.useGlobalHubs' => 'Usa layout home',
'settings.useGlobalHubsDescription' => 'Mostra hub Home unificati. Altrimenti usa i consigli della libreria.',
'settings.showServerNameOnHubs' => 'Mostra nome server sugli hub',
@@ -2262,8 +2267,8 @@ extension on TranslationsIt {
'mediaMenu.markAsWatched' => 'Segna come visto',
'mediaMenu.markAsUnwatched' => 'Segna come non visto',
'mediaMenu.removeFromContinueWatching' => 'Rimuovi da Continua a guardare',
'mediaMenu.viewDetails' => 'Vedi dettagli',
'mediaMenu.goToSeries' => 'Vai alle serie',
'mediaMenu.goToSeason' => 'Vai alla stagione',
'mediaMenu.shufflePlay' => 'Riproduzione casuale',
'mediaMenu.shuffleNotAvailableOffline' => 'Riproduzione casuale non disponibile offline',
'mediaMenu.fileInfo' => 'Info sul file',
@@ -2395,7 +2400,6 @@ extension on TranslationsIt {
'messages.fileInfoNotAvailable' => 'Informazioni sul file non disponibili',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Errore caricamento informazioni sul file: ${error}',
'messages.errorLoadingSeries' => 'Errore caricamento serie',
'messages.errorLoadingSeason' => 'Errore caricamento stagione',
'messages.musicNotSupported' => 'La riproduzione musicale non è ancora supportata',
'messages.noDescriptionAvailable' => 'Nessuna descrizione disponibile',
'messages.noProfilesAvailable' => 'Nessun profilo disponibile',
@@ -2431,10 +2435,10 @@ extension on TranslationsIt {
'subtitlingStyling.border' => 'Bordo',
'subtitlingStyling.background' => 'Sfondo',
'subtitlingStyling.fontSize' => 'Dimensione',
'subtitlingStyling.textColor' => 'Colore testo',
'subtitlingStyling.borderSize' => 'Dimensione bordo',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Colore testo',
'subtitlingStyling.borderSize' => 'Dimensione bordo',
'subtitlingStyling.borderColor' => 'Colore bordo',
'subtitlingStyling.backgroundOpacity' => 'Opacità sfondo',
'subtitlingStyling.backgroundColor' => 'Colore sfondo',
@@ -2945,10 +2949,10 @@ extension on TranslationsIt {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Navigazione schede',
'companionRemote.remote.tabDiscover' => 'Esplora',
'companionRemote.remote.tabLibraries' => 'Librerie',
'companionRemote.remote.tabSearch' => 'Cerca',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Librerie',
'companionRemote.remote.tabSearch' => 'Cerca',
'companionRemote.remote.tabDownloads' => 'Download',
'companionRemote.remote.tabSettings' => 'Impostazioni',
'companionRemote.remote.previous' => 'Precedente',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsJa extends TranslationsSettingsEn {
@override String get gridView => 'グリッド';
@override String get listView => 'リスト';
@override String get showHeroSection => 'ヒーローセクションを表示';
@override String get continueWatchingAction => '視聴中の操作';
@override String get continueWatchingPlay => '再生';
@override String get continueWatchingDetails => '詳細を開く';
@override String get useGlobalHubs => 'ホームレイアウトを使用';
@override String get useGlobalHubsDescription => '統合ホームハブを表示します。オフの場合はライブラリのおすすめを使用します。';
@override String get showServerNameOnHubs => 'ハブにサーバー名を表示';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuJa extends TranslationsMediaMenuEn {
@override String get markAsWatched => '視聴済みにする';
@override String get markAsUnwatched => '未視聴にする';
@override String get removeFromContinueWatching => '視聴中から削除';
@override String get viewDetails => '詳細を表示';
@override String get goToSeries => 'シリーズへ移動';
@override String get goToSeason => 'シーズンへ移動';
@override String get shufflePlay => 'シャッフル再生';
@override String get shuffleNotAvailableOffline => 'オフラインではシャッフルを利用できません';
@override String get fileInfo => 'ファイル情報';
@@ -673,7 +676,6 @@ class _TranslationsMessagesJa extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'ファイル情報が利用できません';
@override String errorLoadingFileInfo({required Object error}) => 'ファイル情報の読み込みエラー: ${error}';
@override String get errorLoadingSeries => 'シリーズの読み込みエラー';
@override String get errorLoadingSeason => 'シーズンの読み込みエラー';
@override String get musicNotSupported => '音楽の再生はまだサポートされていません';
@override String get noDescriptionAvailable => '説明はありません';
@override String get noProfilesAvailable => '利用可能なプロフィールがありません';
@@ -2027,6 +2029,9 @@ extension on TranslationsJa {
'settings.gridView' => 'グリッド',
'settings.listView' => 'リスト',
'settings.showHeroSection' => 'ヒーローセクションを表示',
'settings.continueWatchingAction' => '視聴中の操作',
'settings.continueWatchingPlay' => '再生',
'settings.continueWatchingDetails' => '詳細を開く',
'settings.useGlobalHubs' => 'ホームレイアウトを使用',
'settings.useGlobalHubsDescription' => '統合ホームハブを表示します。オフの場合はライブラリのおすすめを使用します。',
'settings.showServerNameOnHubs' => 'ハブにサーバー名を表示',
@@ -2262,8 +2267,8 @@ extension on TranslationsJa {
'mediaMenu.markAsWatched' => '視聴済みにする',
'mediaMenu.markAsUnwatched' => '未視聴にする',
'mediaMenu.removeFromContinueWatching' => '視聴中から削除',
'mediaMenu.viewDetails' => '詳細を表示',
'mediaMenu.goToSeries' => 'シリーズへ移動',
'mediaMenu.goToSeason' => 'シーズンへ移動',
'mediaMenu.shufflePlay' => 'シャッフル再生',
'mediaMenu.shuffleNotAvailableOffline' => 'オフラインではシャッフルを利用できません',
'mediaMenu.fileInfo' => 'ファイル情報',
@@ -2395,7 +2400,6 @@ extension on TranslationsJa {
'messages.fileInfoNotAvailable' => 'ファイル情報が利用できません',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'ファイル情報の読み込みエラー: ${error}',
'messages.errorLoadingSeries' => 'シリーズの読み込みエラー',
'messages.errorLoadingSeason' => 'シーズンの読み込みエラー',
'messages.musicNotSupported' => '音楽の再生はまだサポートされていません',
'messages.noDescriptionAvailable' => '説明はありません',
'messages.noProfilesAvailable' => '利用可能なプロフィールがありません',
@@ -2431,10 +2435,10 @@ extension on TranslationsJa {
'subtitlingStyling.border' => '枠線',
'subtitlingStyling.background' => '背景',
'subtitlingStyling.fontSize' => 'フォントサイズ',
'subtitlingStyling.textColor' => 'テキストの色',
'subtitlingStyling.borderSize' => '枠線サイズ',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'テキストの色',
'subtitlingStyling.borderSize' => '枠線サイズ',
'subtitlingStyling.borderColor' => '枠線の色',
'subtitlingStyling.backgroundOpacity' => '背景の不透明度',
'subtitlingStyling.backgroundColor' => '背景色',
@@ -2945,10 +2949,10 @@ extension on TranslationsJa {
'companionRemote.remote.menu' => 'メニュー',
'companionRemote.remote.tabNavigation' => 'タブナビゲーション',
'companionRemote.remote.tabDiscover' => '探す',
'companionRemote.remote.tabLibraries' => 'ライブラリ',
'companionRemote.remote.tabSearch' => '検索',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'ライブラリ',
'companionRemote.remote.tabSearch' => '検索',
'companionRemote.remote.tabDownloads' => 'ダウンロード',
'companionRemote.remote.tabSettings' => '設定',
'companionRemote.remote.previous' => '前へ',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsKo extends TranslationsSettingsEn {
@override String get gridView => '그리드 보기';
@override String get listView => '목록 보기';
@override String get showHeroSection => '주요 추천 영역 표시';
@override String get continueWatchingAction => '계속 보기 동작';
@override String get continueWatchingPlay => '재생';
@override String get continueWatchingDetails => '상세 정보 열기';
@override String get useGlobalHubs => '홈 레이아웃 사용';
@override String get useGlobalHubsDescription => '통합 홈 허브를 표시합니다. 끄면 라이브러리 추천을 사용합니다.';
@override String get showServerNameOnHubs => '허브에 서버 이름 표시';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuKo extends TranslationsMediaMenuEn {
@override String get markAsWatched => '시청 완료로 표시';
@override String get markAsUnwatched => '시청 안 함으로 표시';
@override String get removeFromContinueWatching => '계속 보기에서 제거';
@override String get viewDetails => '상세 정보 보기';
@override String get goToSeries => '시리즈로 이동';
@override String get goToSeason => '시즌으로 이동';
@override String get shufflePlay => '무작위 재생';
@override String get shuffleNotAvailableOffline => '오프라인에서는 셔플을 사용할 수 없습니다';
@override String get fileInfo => '파일 정보';
@@ -673,7 +676,6 @@ class _TranslationsMessagesKo extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => '파일 정보가 없습니다';
@override String errorLoadingFileInfo({required Object error}) => '파일 정보 로딩 중 오류: ${error}';
@override String get errorLoadingSeries => '시리즈 로딩 중 오류';
@override String get errorLoadingSeason => '시즌 로딩 중 오류';
@override String get musicNotSupported => '음악 재생 미지원';
@override String get noDescriptionAvailable => '설명이 없습니다';
@override String get noProfilesAvailable => '사용 가능한 프로필이 없습니다';
@@ -2027,6 +2029,9 @@ extension on TranslationsKo {
'settings.gridView' => '그리드 보기',
'settings.listView' => '목록 보기',
'settings.showHeroSection' => '주요 추천 영역 표시',
'settings.continueWatchingAction' => '계속 보기 동작',
'settings.continueWatchingPlay' => '재생',
'settings.continueWatchingDetails' => '상세 정보 열기',
'settings.useGlobalHubs' => '홈 레이아웃 사용',
'settings.useGlobalHubsDescription' => '통합 홈 허브를 표시합니다. 끄면 라이브러리 추천을 사용합니다.',
'settings.showServerNameOnHubs' => '허브에 서버 이름 표시',
@@ -2262,8 +2267,8 @@ extension on TranslationsKo {
'mediaMenu.markAsWatched' => '시청 완료로 표시',
'mediaMenu.markAsUnwatched' => '시청 안 함으로 표시',
'mediaMenu.removeFromContinueWatching' => '계속 보기에서 제거',
'mediaMenu.viewDetails' => '상세 정보 보기',
'mediaMenu.goToSeries' => '시리즈로 이동',
'mediaMenu.goToSeason' => '시즌으로 이동',
'mediaMenu.shufflePlay' => '무작위 재생',
'mediaMenu.shuffleNotAvailableOffline' => '오프라인에서는 셔플을 사용할 수 없습니다',
'mediaMenu.fileInfo' => '파일 정보',
@@ -2395,7 +2400,6 @@ extension on TranslationsKo {
'messages.fileInfoNotAvailable' => '파일 정보가 없습니다',
'messages.errorLoadingFileInfo' => ({required Object error}) => '파일 정보 로딩 중 오류: ${error}',
'messages.errorLoadingSeries' => '시리즈 로딩 중 오류',
'messages.errorLoadingSeason' => '시즌 로딩 중 오류',
'messages.musicNotSupported' => '음악 재생 미지원',
'messages.noDescriptionAvailable' => '설명이 없습니다',
'messages.noProfilesAvailable' => '사용 가능한 프로필이 없습니다',
@@ -2431,10 +2435,10 @@ extension on TranslationsKo {
'subtitlingStyling.border' => '테두리',
'subtitlingStyling.background' => '배경',
'subtitlingStyling.fontSize' => '글자 크기',
'subtitlingStyling.textColor' => '텍스트 색상',
'subtitlingStyling.borderSize' => '테두리 크기',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => '텍스트 색상',
'subtitlingStyling.borderSize' => '테두리 크기',
'subtitlingStyling.borderColor' => '테두리 색상',
'subtitlingStyling.backgroundOpacity' => '배경 불투명도',
'subtitlingStyling.backgroundColor' => '배경색',
@@ -2945,10 +2949,10 @@ extension on TranslationsKo {
'companionRemote.remote.menu' => '메뉴',
'companionRemote.remote.tabNavigation' => '탭 탐색',
'companionRemote.remote.tabDiscover' => '발견',
'companionRemote.remote.tabLibraries' => '미디어 라이브러리',
'companionRemote.remote.tabSearch' => '검색',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => '미디어 라이브러리',
'companionRemote.remote.tabSearch' => '검색',
'companionRemote.remote.tabDownloads' => '다운로드',
'companionRemote.remote.tabSettings' => '설정',
'companionRemote.remote.previous' => '이전',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsNb extends TranslationsSettingsEn {
@override String get gridView => 'Rutenett';
@override String get listView => 'Liste';
@override String get showHeroSection => 'Vis fremhevet seksjon';
@override String get continueWatchingAction => 'Handling for Fortsett å se';
@override String get continueWatchingPlay => 'Spill av';
@override String get continueWatchingDetails => 'Åpne detaljer';
@override String get useGlobalHubs => 'Bruk startoppsett';
@override String get useGlobalHubsDescription => 'Vis samlet startinnhold. Ellers brukes bibliotekanbefalinger.';
@override String get showServerNameOnHubs => 'Vis servernavn på huber';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuNb extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Merk som sett';
@override String get markAsUnwatched => 'Merk som usett';
@override String get removeFromContinueWatching => 'Fjern fra Fortsett å se';
@override String get viewDetails => 'Vis detaljer';
@override String get goToSeries => 'Gå til serie';
@override String get goToSeason => 'Gå til sesong';
@override String get shufflePlay => 'Tilfeldig avspilling';
@override String get shuffleNotAvailableOffline => 'Tilfeldig avspilling er ikke tilgjengelig offline';
@override String get fileInfo => 'Filinformasjon';
@@ -673,7 +676,6 @@ class _TranslationsMessagesNb extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Filinformasjon ikke tilgjengelig';
@override String errorLoadingFileInfo({required Object error}) => 'Feil ved lasting av filinformasjon: ${error}';
@override String get errorLoadingSeries => 'Feil ved lasting av serie';
@override String get errorLoadingSeason => 'Feil ved lasting av sesong';
@override String get musicNotSupported => 'Musikkavspilling støttes ikke ennå';
@override String get noDescriptionAvailable => 'Ingen beskrivelse tilgjengelig';
@override String get noProfilesAvailable => 'Ingen profiler tilgjengelige';
@@ -2027,6 +2029,9 @@ extension on TranslationsNb {
'settings.gridView' => 'Rutenett',
'settings.listView' => 'Liste',
'settings.showHeroSection' => 'Vis fremhevet seksjon',
'settings.continueWatchingAction' => 'Handling for Fortsett å se',
'settings.continueWatchingPlay' => 'Spill av',
'settings.continueWatchingDetails' => 'Åpne detaljer',
'settings.useGlobalHubs' => 'Bruk startoppsett',
'settings.useGlobalHubsDescription' => 'Vis samlet startinnhold. Ellers brukes bibliotekanbefalinger.',
'settings.showServerNameOnHubs' => 'Vis servernavn på huber',
@@ -2262,8 +2267,8 @@ extension on TranslationsNb {
'mediaMenu.markAsWatched' => 'Merk som sett',
'mediaMenu.markAsUnwatched' => 'Merk som usett',
'mediaMenu.removeFromContinueWatching' => 'Fjern fra Fortsett å se',
'mediaMenu.viewDetails' => 'Vis detaljer',
'mediaMenu.goToSeries' => 'Gå til serie',
'mediaMenu.goToSeason' => 'Gå til sesong',
'mediaMenu.shufflePlay' => 'Tilfeldig avspilling',
'mediaMenu.shuffleNotAvailableOffline' => 'Tilfeldig avspilling er ikke tilgjengelig offline',
'mediaMenu.fileInfo' => 'Filinformasjon',
@@ -2395,7 +2400,6 @@ extension on TranslationsNb {
'messages.fileInfoNotAvailable' => 'Filinformasjon ikke tilgjengelig',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Feil ved lasting av filinformasjon: ${error}',
'messages.errorLoadingSeries' => 'Feil ved lasting av serie',
'messages.errorLoadingSeason' => 'Feil ved lasting av sesong',
'messages.musicNotSupported' => 'Musikkavspilling støttes ikke ennå',
'messages.noDescriptionAvailable' => 'Ingen beskrivelse tilgjengelig',
'messages.noProfilesAvailable' => 'Ingen profiler tilgjengelige',
@@ -2431,10 +2435,10 @@ extension on TranslationsNb {
'subtitlingStyling.border' => 'Kantlinje',
'subtitlingStyling.background' => 'Bakgrunn',
'subtitlingStyling.fontSize' => 'Skriftstørrelse',
'subtitlingStyling.textColor' => 'Tekstfarge',
'subtitlingStyling.borderSize' => 'Kantstørrelse',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Tekstfarge',
'subtitlingStyling.borderSize' => 'Kantstørrelse',
'subtitlingStyling.borderColor' => 'Kantfarge',
'subtitlingStyling.backgroundOpacity' => 'Bakgrunnsopasitet',
'subtitlingStyling.backgroundColor' => 'Bakgrunnsfarge',
@@ -2945,10 +2949,10 @@ extension on TranslationsNb {
'companionRemote.remote.menu' => 'Meny',
'companionRemote.remote.tabNavigation' => 'Fanenavigering',
'companionRemote.remote.tabDiscover' => 'Oppdag',
'companionRemote.remote.tabLibraries' => 'Biblioteker',
'companionRemote.remote.tabSearch' => 'Søk',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Biblioteker',
'companionRemote.remote.tabSearch' => 'Søk',
'companionRemote.remote.tabDownloads' => 'Nedlastinger',
'companionRemote.remote.tabSettings' => 'Innstillinger',
'companionRemote.remote.previous' => 'Forrige',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsNl extends TranslationsSettingsEn {
@override String get gridView => 'Raster';
@override String get listView => 'Lijst';
@override String get showHeroSection => 'Toon hoofdsectie';
@override String get continueWatchingAction => 'Actie voor Doorgaan met kijken';
@override String get continueWatchingPlay => 'Afspelen';
@override String get continueWatchingDetails => 'Details openen';
@override String get useGlobalHubs => 'Startlayout gebruiken';
@override String get useGlobalHubsDescription => 'Toon gecombineerde home-hubs. Anders bibliotheekaanbevelingen gebruiken.';
@override String get showServerNameOnHubs => 'Servernaam tonen bij hubs';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuNl extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Markeer als gekeken';
@override String get markAsUnwatched => 'Markeer als ongekeken';
@override String get removeFromContinueWatching => 'Verwijder uit Doorgaan met kijken';
@override String get viewDetails => 'Details bekijken';
@override String get goToSeries => 'Ga naar serie';
@override String get goToSeason => 'Ga naar seizoen';
@override String get shufflePlay => 'Willekeurig afspelen';
@override String get shuffleNotAvailableOffline => 'Shuffle is offline niet beschikbaar';
@override String get fileInfo => 'Bestand info';
@@ -673,7 +676,6 @@ class _TranslationsMessagesNl extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Bestand informatie niet beschikbaar';
@override String errorLoadingFileInfo({required Object error}) => 'Fout bij laden bestand info: ${error}';
@override String get errorLoadingSeries => 'Fout bij laden serie';
@override String get errorLoadingSeason => 'Fout bij laden seizoen';
@override String get musicNotSupported => 'Muziek afspelen wordt nog niet ondersteund';
@override String get noDescriptionAvailable => 'Geen beschrijving beschikbaar';
@override String get noProfilesAvailable => 'Geen profielen beschikbaar';
@@ -2027,6 +2029,9 @@ extension on TranslationsNl {
'settings.gridView' => 'Raster',
'settings.listView' => 'Lijst',
'settings.showHeroSection' => 'Toon hoofdsectie',
'settings.continueWatchingAction' => 'Actie voor Doorgaan met kijken',
'settings.continueWatchingPlay' => 'Afspelen',
'settings.continueWatchingDetails' => 'Details openen',
'settings.useGlobalHubs' => 'Startlayout gebruiken',
'settings.useGlobalHubsDescription' => 'Toon gecombineerde home-hubs. Anders bibliotheekaanbevelingen gebruiken.',
'settings.showServerNameOnHubs' => 'Servernaam tonen bij hubs',
@@ -2262,8 +2267,8 @@ extension on TranslationsNl {
'mediaMenu.markAsWatched' => 'Markeer als gekeken',
'mediaMenu.markAsUnwatched' => 'Markeer als ongekeken',
'mediaMenu.removeFromContinueWatching' => 'Verwijder uit Doorgaan met kijken',
'mediaMenu.viewDetails' => 'Details bekijken',
'mediaMenu.goToSeries' => 'Ga naar serie',
'mediaMenu.goToSeason' => 'Ga naar seizoen',
'mediaMenu.shufflePlay' => 'Willekeurig afspelen',
'mediaMenu.shuffleNotAvailableOffline' => 'Shuffle is offline niet beschikbaar',
'mediaMenu.fileInfo' => 'Bestand info',
@@ -2395,7 +2400,6 @@ extension on TranslationsNl {
'messages.fileInfoNotAvailable' => 'Bestand informatie niet beschikbaar',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Fout bij laden bestand info: ${error}',
'messages.errorLoadingSeries' => 'Fout bij laden serie',
'messages.errorLoadingSeason' => 'Fout bij laden seizoen',
'messages.musicNotSupported' => 'Muziek afspelen wordt nog niet ondersteund',
'messages.noDescriptionAvailable' => 'Geen beschrijving beschikbaar',
'messages.noProfilesAvailable' => 'Geen profielen beschikbaar',
@@ -2431,10 +2435,10 @@ extension on TranslationsNl {
'subtitlingStyling.border' => 'Rand',
'subtitlingStyling.background' => 'Achtergrond',
'subtitlingStyling.fontSize' => 'Lettergrootte',
'subtitlingStyling.textColor' => 'Tekstkleur',
'subtitlingStyling.borderSize' => 'Rand grootte',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Tekstkleur',
'subtitlingStyling.borderSize' => 'Rand grootte',
'subtitlingStyling.borderColor' => 'Randkleur',
'subtitlingStyling.backgroundOpacity' => 'Achtergrond transparantie',
'subtitlingStyling.backgroundColor' => 'Achtergrondkleur',
@@ -2945,10 +2949,10 @@ extension on TranslationsNl {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Tabnavigatie',
'companionRemote.remote.tabDiscover' => 'Ontdekken',
'companionRemote.remote.tabLibraries' => 'Bibliotheken',
'companionRemote.remote.tabSearch' => 'Zoeken',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Bibliotheken',
'companionRemote.remote.tabSearch' => 'Zoeken',
'companionRemote.remote.tabDownloads' => 'Downloads',
'companionRemote.remote.tabSettings' => 'Instellingen',
'companionRemote.remote.previous' => 'Vorige',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsPl extends TranslationsSettingsEn {
@override String get gridView => 'Siatka';
@override String get listView => 'Lista';
@override String get showHeroSection => 'Pokaż sekcję wyróżnioną';
@override String get continueWatchingAction => 'Akcja Kontynuuj oglądanie';
@override String get continueWatchingPlay => 'Odtwórz';
@override String get continueWatchingDetails => 'Otwórz szczegóły';
@override String get useGlobalHubs => 'Użyj układu strony głównej';
@override String get useGlobalHubsDescription => 'Pokaż ujednolicone huby ekranu głównego. W przeciwnym razie użyj rekomendacji bibliotek.';
@override String get showServerNameOnHubs => 'Pokaż nazwę serwera w hubach';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuPl extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Oznacz jako obejrzane';
@override String get markAsUnwatched => 'Oznacz jako nieobejrzane';
@override String get removeFromContinueWatching => 'Usuń z kontynuowania oglądania';
@override String get viewDetails => 'Pokaż szczegóły';
@override String get goToSeries => 'Przejdź do serialu';
@override String get goToSeason => 'Przejdź do sezonu';
@override String get shufflePlay => 'Odtwarzanie losowe';
@override String get shuffleNotAvailableOffline => 'Odtwarzanie losowe nie jest dostępne offline';
@override String get fileInfo => 'Informacje o pliku';
@@ -673,7 +676,6 @@ class _TranslationsMessagesPl extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Informacje o pliku niedostępne';
@override String errorLoadingFileInfo({required Object error}) => 'Błąd ładowania informacji o pliku: ${error}';
@override String get errorLoadingSeries => 'Błąd ładowania serialu';
@override String get errorLoadingSeason => 'Błąd ładowania sezonu';
@override String get musicNotSupported => 'Odtwarzanie muzyki nie jest jeszcze obsługiwane';
@override String get noDescriptionAvailable => 'Brak dostępnego opisu';
@override String get noProfilesAvailable => 'Brak dostępnych profili';
@@ -2027,6 +2029,9 @@ extension on TranslationsPl {
'settings.gridView' => 'Siatka',
'settings.listView' => 'Lista',
'settings.showHeroSection' => 'Pokaż sekcję wyróżnioną',
'settings.continueWatchingAction' => 'Akcja Kontynuuj oglądanie',
'settings.continueWatchingPlay' => 'Odtwórz',
'settings.continueWatchingDetails' => 'Otwórz szczegóły',
'settings.useGlobalHubs' => 'Użyj układu strony głównej',
'settings.useGlobalHubsDescription' => 'Pokaż ujednolicone huby ekranu głównego. W przeciwnym razie użyj rekomendacji bibliotek.',
'settings.showServerNameOnHubs' => 'Pokaż nazwę serwera w hubach',
@@ -2262,8 +2267,8 @@ extension on TranslationsPl {
'mediaMenu.markAsWatched' => 'Oznacz jako obejrzane',
'mediaMenu.markAsUnwatched' => 'Oznacz jako nieobejrzane',
'mediaMenu.removeFromContinueWatching' => 'Usuń z kontynuowania oglądania',
'mediaMenu.viewDetails' => 'Pokaż szczegóły',
'mediaMenu.goToSeries' => 'Przejdź do serialu',
'mediaMenu.goToSeason' => 'Przejdź do sezonu',
'mediaMenu.shufflePlay' => 'Odtwarzanie losowe',
'mediaMenu.shuffleNotAvailableOffline' => 'Odtwarzanie losowe nie jest dostępne offline',
'mediaMenu.fileInfo' => 'Informacje o pliku',
@@ -2395,7 +2400,6 @@ extension on TranslationsPl {
'messages.fileInfoNotAvailable' => 'Informacje o pliku niedostępne',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Błąd ładowania informacji o pliku: ${error}',
'messages.errorLoadingSeries' => 'Błąd ładowania serialu',
'messages.errorLoadingSeason' => 'Błąd ładowania sezonu',
'messages.musicNotSupported' => 'Odtwarzanie muzyki nie jest jeszcze obsługiwane',
'messages.noDescriptionAvailable' => 'Brak dostępnego opisu',
'messages.noProfilesAvailable' => 'Brak dostępnych profili',
@@ -2431,10 +2435,10 @@ extension on TranslationsPl {
'subtitlingStyling.border' => 'Obramowanie',
'subtitlingStyling.background' => 'Tło',
'subtitlingStyling.fontSize' => 'Rozmiar czcionki',
'subtitlingStyling.textColor' => 'Kolor tekstu',
'subtitlingStyling.borderSize' => 'Rozmiar obramowania',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Kolor tekstu',
'subtitlingStyling.borderSize' => 'Rozmiar obramowania',
'subtitlingStyling.borderColor' => 'Kolor obramowania',
'subtitlingStyling.backgroundOpacity' => 'Przezroczystość tła',
'subtitlingStyling.backgroundColor' => 'Kolor tła',
@@ -2945,10 +2949,10 @@ extension on TranslationsPl {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Nawigacja',
'companionRemote.remote.tabDiscover' => 'Odkryj',
'companionRemote.remote.tabLibraries' => 'Biblioteki',
'companionRemote.remote.tabSearch' => 'Szukaj',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Biblioteki',
'companionRemote.remote.tabSearch' => 'Szukaj',
'companionRemote.remote.tabDownloads' => 'Pobrania',
'companionRemote.remote.tabSettings' => 'Ustawienia',
'companionRemote.remote.previous' => 'Poprzedni',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsPt extends TranslationsSettingsEn {
@override String get gridView => 'Grade';
@override String get listView => 'Lista';
@override String get showHeroSection => 'Mostrar Seção de Destaque';
@override String get continueWatchingAction => 'Ação de Continuar Assistindo';
@override String get continueWatchingPlay => 'Reproduzir';
@override String get continueWatchingDetails => 'Abrir detalhes';
@override String get useGlobalHubs => 'Usar layout inicial';
@override String get useGlobalHubsDescription => 'Mostrar hubs iniciais unificados. Caso contrário, usar recomendações da biblioteca.';
@override String get showServerNameOnHubs => 'Mostrar Nome do Servidor nos Hubs';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuPt extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Marcar como Assistido';
@override String get markAsUnwatched => 'Marcar como Não Assistido';
@override String get removeFromContinueWatching => 'Remover de Continuar Assistindo';
@override String get viewDetails => 'Ver detalhes';
@override String get goToSeries => 'Ir para a série';
@override String get goToSeason => 'Ir para a temporada';
@override String get shufflePlay => 'Reprodução Aleatória';
@override String get shuffleNotAvailableOffline => 'Reprodução aleatória indisponível offline';
@override String get fileInfo => 'Info do Arquivo';
@@ -673,7 +676,6 @@ class _TranslationsMessagesPt extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Informações do arquivo não disponíveis';
@override String errorLoadingFileInfo({required Object error}) => 'Erro ao carregar info do arquivo: ${error}';
@override String get errorLoadingSeries => 'Erro ao carregar série';
@override String get errorLoadingSeason => 'Erro ao carregar temporada';
@override String get musicNotSupported => 'Reprodução de música ainda não é suportada';
@override String get noDescriptionAvailable => 'Nenhuma descrição disponível';
@override String get noProfilesAvailable => 'Nenhum perfil disponível';
@@ -2027,6 +2029,9 @@ extension on TranslationsPt {
'settings.gridView' => 'Grade',
'settings.listView' => 'Lista',
'settings.showHeroSection' => 'Mostrar Seção de Destaque',
'settings.continueWatchingAction' => 'Ação de Continuar Assistindo',
'settings.continueWatchingPlay' => 'Reproduzir',
'settings.continueWatchingDetails' => 'Abrir detalhes',
'settings.useGlobalHubs' => 'Usar layout inicial',
'settings.useGlobalHubsDescription' => 'Mostrar hubs iniciais unificados. Caso contrário, usar recomendações da biblioteca.',
'settings.showServerNameOnHubs' => 'Mostrar Nome do Servidor nos Hubs',
@@ -2262,8 +2267,8 @@ extension on TranslationsPt {
'mediaMenu.markAsWatched' => 'Marcar como Assistido',
'mediaMenu.markAsUnwatched' => 'Marcar como Não Assistido',
'mediaMenu.removeFromContinueWatching' => 'Remover de Continuar Assistindo',
'mediaMenu.viewDetails' => 'Ver detalhes',
'mediaMenu.goToSeries' => 'Ir para a série',
'mediaMenu.goToSeason' => 'Ir para a temporada',
'mediaMenu.shufflePlay' => 'Reprodução Aleatória',
'mediaMenu.shuffleNotAvailableOffline' => 'Reprodução aleatória indisponível offline',
'mediaMenu.fileInfo' => 'Info do Arquivo',
@@ -2395,7 +2400,6 @@ extension on TranslationsPt {
'messages.fileInfoNotAvailable' => 'Informações do arquivo não disponíveis',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Erro ao carregar info do arquivo: ${error}',
'messages.errorLoadingSeries' => 'Erro ao carregar série',
'messages.errorLoadingSeason' => 'Erro ao carregar temporada',
'messages.musicNotSupported' => 'Reprodução de música ainda não é suportada',
'messages.noDescriptionAvailable' => 'Nenhuma descrição disponível',
'messages.noProfilesAvailable' => 'Nenhum perfil disponível',
@@ -2431,10 +2435,10 @@ extension on TranslationsPt {
'subtitlingStyling.border' => 'Borda',
'subtitlingStyling.background' => 'Fundo',
'subtitlingStyling.fontSize' => 'Tamanho da Fonte',
'subtitlingStyling.textColor' => 'Cor do Texto',
'subtitlingStyling.borderSize' => 'Tamanho da Borda',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Cor do Texto',
'subtitlingStyling.borderSize' => 'Tamanho da Borda',
'subtitlingStyling.borderColor' => 'Cor da Borda',
'subtitlingStyling.backgroundOpacity' => 'Opacidade do Fundo',
'subtitlingStyling.backgroundColor' => 'Cor de Fundo',
@@ -2945,10 +2949,10 @@ extension on TranslationsPt {
'companionRemote.remote.menu' => 'Menu',
'companionRemote.remote.tabNavigation' => 'Navegação',
'companionRemote.remote.tabDiscover' => 'Descobrir',
'companionRemote.remote.tabLibraries' => 'Bibliotecas',
'companionRemote.remote.tabSearch' => 'Buscar',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Bibliotecas',
'companionRemote.remote.tabSearch' => 'Buscar',
'companionRemote.remote.tabDownloads' => 'Downloads',
'companionRemote.remote.tabSettings' => 'Configurações',
'companionRemote.remote.previous' => 'Anterior',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsRu extends TranslationsSettingsEn {
@override String get gridView => 'Сетка';
@override String get listView => 'Список';
@override String get showHeroSection => 'Показать раздел избранного';
@override String get continueWatchingAction => 'Действие для «Продолжить просмотр»';
@override String get continueWatchingPlay => 'Воспроизвести';
@override String get continueWatchingDetails => 'Открыть сведения';
@override String get useGlobalHubs => 'Использовать макет главной';
@override String get useGlobalHubsDescription => 'Показывать единые разделы главной. Иначе использовать рекомендации библиотек.';
@override String get showServerNameOnHubs => 'Показывать имя сервера в хабах';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuRu extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Отметить как просмотренное';
@override String get markAsUnwatched => 'Отметить как непросмотренное';
@override String get removeFromContinueWatching => 'Удалить из «Продолжить просмотр»';
@override String get viewDetails => 'Показать сведения';
@override String get goToSeries => 'Перейти к сериалу';
@override String get goToSeason => 'Перейти к сезону';
@override String get shufflePlay => 'Случайное воспроизведение';
@override String get shuffleNotAvailableOffline => 'Перемешивание недоступно офлайн';
@override String get fileInfo => 'Информация о файле';
@@ -673,7 +676,6 @@ class _TranslationsMessagesRu extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Информация о файле недоступна';
@override String errorLoadingFileInfo({required Object error}) => 'Ошибка загрузки информации о файле: ${error}';
@override String get errorLoadingSeries => 'Ошибка загрузки сериала';
@override String get errorLoadingSeason => 'Ошибка загрузки сезона';
@override String get musicNotSupported => 'Воспроизведение музыки пока не поддерживается';
@override String get noDescriptionAvailable => 'Описание недоступно';
@override String get noProfilesAvailable => 'Профили недоступны';
@@ -2027,6 +2029,9 @@ extension on TranslationsRu {
'settings.gridView' => 'Сетка',
'settings.listView' => 'Список',
'settings.showHeroSection' => 'Показать раздел избранного',
'settings.continueWatchingAction' => 'Действие для «Продолжить просмотр»',
'settings.continueWatchingPlay' => 'Воспроизвести',
'settings.continueWatchingDetails' => 'Открыть сведения',
'settings.useGlobalHubs' => 'Использовать макет главной',
'settings.useGlobalHubsDescription' => 'Показывать единые разделы главной. Иначе использовать рекомендации библиотек.',
'settings.showServerNameOnHubs' => 'Показывать имя сервера в хабах',
@@ -2262,8 +2267,8 @@ extension on TranslationsRu {
'mediaMenu.markAsWatched' => 'Отметить как просмотренное',
'mediaMenu.markAsUnwatched' => 'Отметить как непросмотренное',
'mediaMenu.removeFromContinueWatching' => 'Удалить из «Продолжить просмотр»',
'mediaMenu.viewDetails' => 'Показать сведения',
'mediaMenu.goToSeries' => 'Перейти к сериалу',
'mediaMenu.goToSeason' => 'Перейти к сезону',
'mediaMenu.shufflePlay' => 'Случайное воспроизведение',
'mediaMenu.shuffleNotAvailableOffline' => 'Перемешивание недоступно офлайн',
'mediaMenu.fileInfo' => 'Информация о файле',
@@ -2395,7 +2400,6 @@ extension on TranslationsRu {
'messages.fileInfoNotAvailable' => 'Информация о файле недоступна',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Ошибка загрузки информации о файле: ${error}',
'messages.errorLoadingSeries' => 'Ошибка загрузки сериала',
'messages.errorLoadingSeason' => 'Ошибка загрузки сезона',
'messages.musicNotSupported' => 'Воспроизведение музыки пока не поддерживается',
'messages.noDescriptionAvailable' => 'Описание недоступно',
'messages.noProfilesAvailable' => 'Профили недоступны',
@@ -2431,10 +2435,10 @@ extension on TranslationsRu {
'subtitlingStyling.border' => 'Обводка',
'subtitlingStyling.background' => 'Фон',
'subtitlingStyling.fontSize' => 'Размер шрифта',
'subtitlingStyling.textColor' => 'Цвет текста',
'subtitlingStyling.borderSize' => 'Размер обводки',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Цвет текста',
'subtitlingStyling.borderSize' => 'Размер обводки',
'subtitlingStyling.borderColor' => 'Цвет обводки',
'subtitlingStyling.backgroundOpacity' => 'Прозрачность фона',
'subtitlingStyling.backgroundColor' => 'Цвет фона',
@@ -2945,10 +2949,10 @@ extension on TranslationsRu {
'companionRemote.remote.menu' => 'Меню',
'companionRemote.remote.tabNavigation' => 'Навигация',
'companionRemote.remote.tabDiscover' => 'Обзор',
'companionRemote.remote.tabLibraries' => 'Библиотеки',
'companionRemote.remote.tabSearch' => 'Поиск',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Библиотеки',
'companionRemote.remote.tabSearch' => 'Поиск',
'companionRemote.remote.tabDownloads' => 'Загрузки',
'companionRemote.remote.tabSettings' => 'Настройки',
'companionRemote.remote.previous' => 'Предыдущий',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsSv extends TranslationsSettingsEn {
@override String get gridView => 'Rutnät';
@override String get listView => 'Lista';
@override String get showHeroSection => 'Visa hjältesektion';
@override String get continueWatchingAction => 'Åtgärd för Fortsätt titta';
@override String get continueWatchingPlay => 'Spela';
@override String get continueWatchingDetails => 'Öppna detaljer';
@override String get useGlobalHubs => 'Använd startlayout';
@override String get useGlobalHubsDescription => 'Visa enhetliga startsideshubbar. Annars används biblioteksrekommendationer.';
@override String get showServerNameOnHubs => 'Visa servernamn på hubbar';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuSv extends TranslationsMediaMenuEn {
@override String get markAsWatched => 'Markera som sedd';
@override String get markAsUnwatched => 'Markera som osedd';
@override String get removeFromContinueWatching => 'Ta bort från Fortsätt titta';
@override String get viewDetails => 'Visa detaljer';
@override String get goToSeries => 'Gå till serie';
@override String get goToSeason => 'Gå till säsong';
@override String get shufflePlay => 'Blanda uppspelning';
@override String get shuffleNotAvailableOffline => 'Blandad uppspelning är inte tillgänglig offline';
@override String get fileInfo => 'Filinformation';
@@ -673,7 +676,6 @@ class _TranslationsMessagesSv extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => 'Filinformation inte tillgänglig';
@override String errorLoadingFileInfo({required Object error}) => 'Fel vid laddning av filinformation: ${error}';
@override String get errorLoadingSeries => 'Fel vid laddning av serie';
@override String get errorLoadingSeason => 'Fel vid laddning av säsong';
@override String get musicNotSupported => 'Musikuppspelning stöds inte ännu';
@override String get noDescriptionAvailable => 'Ingen beskrivning tillgänglig';
@override String get noProfilesAvailable => 'Inga profiler tillgängliga';
@@ -2027,6 +2029,9 @@ extension on TranslationsSv {
'settings.gridView' => 'Rutnät',
'settings.listView' => 'Lista',
'settings.showHeroSection' => 'Visa hjältesektion',
'settings.continueWatchingAction' => 'Åtgärd för Fortsätt titta',
'settings.continueWatchingPlay' => 'Spela',
'settings.continueWatchingDetails' => 'Öppna detaljer',
'settings.useGlobalHubs' => 'Använd startlayout',
'settings.useGlobalHubsDescription' => 'Visa enhetliga startsideshubbar. Annars används biblioteksrekommendationer.',
'settings.showServerNameOnHubs' => 'Visa servernamn på hubbar',
@@ -2262,8 +2267,8 @@ extension on TranslationsSv {
'mediaMenu.markAsWatched' => 'Markera som sedd',
'mediaMenu.markAsUnwatched' => 'Markera som osedd',
'mediaMenu.removeFromContinueWatching' => 'Ta bort från Fortsätt titta',
'mediaMenu.viewDetails' => 'Visa detaljer',
'mediaMenu.goToSeries' => 'Gå till serie',
'mediaMenu.goToSeason' => 'Gå till säsong',
'mediaMenu.shufflePlay' => 'Blanda uppspelning',
'mediaMenu.shuffleNotAvailableOffline' => 'Blandad uppspelning är inte tillgänglig offline',
'mediaMenu.fileInfo' => 'Filinformation',
@@ -2395,7 +2400,6 @@ extension on TranslationsSv {
'messages.fileInfoNotAvailable' => 'Filinformation inte tillgänglig',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Fel vid laddning av filinformation: ${error}',
'messages.errorLoadingSeries' => 'Fel vid laddning av serie',
'messages.errorLoadingSeason' => 'Fel vid laddning av säsong',
'messages.musicNotSupported' => 'Musikuppspelning stöds inte ännu',
'messages.noDescriptionAvailable' => 'Ingen beskrivning tillgänglig',
'messages.noProfilesAvailable' => 'Inga profiler tillgängliga',
@@ -2431,10 +2435,10 @@ extension on TranslationsSv {
'subtitlingStyling.border' => 'Kantlinje',
'subtitlingStyling.background' => 'Bakgrund',
'subtitlingStyling.fontSize' => 'Teckenstorlek',
'subtitlingStyling.textColor' => 'Textfärg',
'subtitlingStyling.borderSize' => 'Kantstorlek',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => 'Textfärg',
'subtitlingStyling.borderSize' => 'Kantstorlek',
'subtitlingStyling.borderColor' => 'Kantfärg',
'subtitlingStyling.backgroundOpacity' => 'Bakgrundsopacitet',
'subtitlingStyling.backgroundColor' => 'Bakgrundsfärg',
@@ -2945,10 +2949,10 @@ extension on TranslationsSv {
'companionRemote.remote.menu' => 'Meny',
'companionRemote.remote.tabNavigation' => 'Fliknavigering',
'companionRemote.remote.tabDiscover' => 'Upptäck',
'companionRemote.remote.tabLibraries' => 'Bibliotek',
'companionRemote.remote.tabSearch' => 'Sök',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => 'Bibliotek',
'companionRemote.remote.tabSearch' => 'Sök',
'companionRemote.remote.tabDownloads' => 'Nedladdningar',
'companionRemote.remote.tabSettings' => 'Inställningar',
'companionRemote.remote.previous' => 'Föregående',
+12 -8
View File
@@ -245,6 +245,9 @@ class _TranslationsSettingsZh extends TranslationsSettingsEn {
@override String get gridView => '网格视图';
@override String get listView => '列表视图';
@override String get showHeroSection => '显示主要精选区';
@override String get continueWatchingAction => '继续观看操作';
@override String get continueWatchingPlay => '播放';
@override String get continueWatchingDetails => '打开详情';
@override String get useGlobalHubs => '使用主页布局';
@override String get useGlobalHubsDescription => '显示统一主页中心。否则使用资料库推荐。';
@override String get showServerNameOnHubs => '在推荐栏显示服务器名称';
@@ -492,8 +495,8 @@ class _TranslationsMediaMenuZh extends TranslationsMediaMenuEn {
@override String get markAsWatched => '标记为已观看';
@override String get markAsUnwatched => '标记为未观看';
@override String get removeFromContinueWatching => '从继续观看中移除';
@override String get viewDetails => '查看详情';
@override String get goToSeries => '转到系列';
@override String get goToSeason => '转到季';
@override String get shufflePlay => '随机播放';
@override String get shuffleNotAvailableOffline => '离线时无法随机播放';
@override String get fileInfo => '文件信息';
@@ -673,7 +676,6 @@ class _TranslationsMessagesZh extends TranslationsMessagesEn {
@override String get fileInfoNotAvailable => '文件信息不可用';
@override String errorLoadingFileInfo({required Object error}) => '加载文件信息时出错: ${error}';
@override String get errorLoadingSeries => '加载系列时出错';
@override String get errorLoadingSeason => '加载季时出错';
@override String get musicNotSupported => '尚不支持播放音乐';
@override String get noDescriptionAvailable => '暂无描述';
@override String get noProfilesAvailable => '没有可用的用户';
@@ -2027,6 +2029,9 @@ extension on TranslationsZh {
'settings.gridView' => '网格视图',
'settings.listView' => '列表视图',
'settings.showHeroSection' => '显示主要精选区',
'settings.continueWatchingAction' => '继续观看操作',
'settings.continueWatchingPlay' => '播放',
'settings.continueWatchingDetails' => '打开详情',
'settings.useGlobalHubs' => '使用主页布局',
'settings.useGlobalHubsDescription' => '显示统一主页中心。否则使用资料库推荐。',
'settings.showServerNameOnHubs' => '在推荐栏显示服务器名称',
@@ -2262,8 +2267,8 @@ extension on TranslationsZh {
'mediaMenu.markAsWatched' => '标记为已观看',
'mediaMenu.markAsUnwatched' => '标记为未观看',
'mediaMenu.removeFromContinueWatching' => '从继续观看中移除',
'mediaMenu.viewDetails' => '查看详情',
'mediaMenu.goToSeries' => '转到系列',
'mediaMenu.goToSeason' => '转到季',
'mediaMenu.shufflePlay' => '随机播放',
'mediaMenu.shuffleNotAvailableOffline' => '离线时无法随机播放',
'mediaMenu.fileInfo' => '文件信息',
@@ -2395,7 +2400,6 @@ extension on TranslationsZh {
'messages.fileInfoNotAvailable' => '文件信息不可用',
'messages.errorLoadingFileInfo' => ({required Object error}) => '加载文件信息时出错: ${error}',
'messages.errorLoadingSeries' => '加载系列时出错',
'messages.errorLoadingSeason' => '加载季时出错',
'messages.musicNotSupported' => '尚不支持播放音乐',
'messages.noDescriptionAvailable' => '暂无描述',
'messages.noProfilesAvailable' => '没有可用的用户',
@@ -2431,10 +2435,10 @@ extension on TranslationsZh {
'subtitlingStyling.border' => '边框',
'subtitlingStyling.background' => '背景',
'subtitlingStyling.fontSize' => '字号',
'subtitlingStyling.textColor' => '文本颜色',
'subtitlingStyling.borderSize' => '边框大小',
_ => null,
} ?? switch (path) {
'subtitlingStyling.textColor' => '文本颜色',
'subtitlingStyling.borderSize' => '边框大小',
'subtitlingStyling.borderColor' => '边框颜色',
'subtitlingStyling.backgroundOpacity' => '背景不透明度',
'subtitlingStyling.backgroundColor' => '背景颜色',
@@ -2945,10 +2949,10 @@ extension on TranslationsZh {
'companionRemote.remote.menu' => '菜单',
'companionRemote.remote.tabNavigation' => '标签导航',
'companionRemote.remote.tabDiscover' => '发现',
'companionRemote.remote.tabLibraries' => '媒体库',
'companionRemote.remote.tabSearch' => '搜索',
_ => null,
} ?? switch (path) {
'companionRemote.remote.tabLibraries' => '媒体库',
'companionRemote.remote.tabSearch' => '搜索',
'companionRemote.remote.tabDownloads' => '下载',
'companionRemote.remote.tabSettings' => '设置',
'companionRemote.remote.previous' => '上一个',
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "Rutnät",
"listView": "Lista",
"showHeroSection": "Visa hjältesektion",
"continueWatchingAction": "Åtgärd för Fortsätt titta",
"continueWatchingPlay": "Spela",
"continueWatchingDetails": "Öppna detaljer",
"useGlobalHubs": "Använd startlayout",
"useGlobalHubsDescription": "Visa enhetliga startsideshubbar. Annars används biblioteksrekommendationer.",
"showServerNameOnHubs": "Visa servernamn på hubbar",
@@ -361,8 +364,8 @@
"markAsWatched": "Markera som sedd",
"markAsUnwatched": "Markera som osedd",
"removeFromContinueWatching": "Ta bort från Fortsätt titta",
"viewDetails": "Visa detaljer",
"goToSeries": "Gå till serie",
"goToSeason": "Gå till säsong",
"shufflePlay": "Blanda uppspelning",
"shuffleNotAvailableOffline": "Blandad uppspelning är inte tillgänglig offline",
"fileInfo": "Filinformation",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "Filinformation inte tillgänglig",
"errorLoadingFileInfo": "Fel vid laddning av filinformation: ${error}",
"errorLoadingSeries": "Fel vid laddning av serie",
"errorLoadingSeason": "Fel vid laddning av säsong",
"musicNotSupported": "Musikuppspelning stöds inte ännu",
"noDescriptionAvailable": "Ingen beskrivning tillgänglig",
"noProfilesAvailable": "Inga profiler tillgängliga",
+4 -2
View File
@@ -116,6 +116,9 @@
"gridView": "网格视图",
"listView": "列表视图",
"showHeroSection": "显示主要精选区",
"continueWatchingAction": "继续观看操作",
"continueWatchingPlay": "播放",
"continueWatchingDetails": "打开详情",
"useGlobalHubs": "使用主页布局",
"useGlobalHubsDescription": "显示统一主页中心。否则使用资料库推荐。",
"showServerNameOnHubs": "在推荐栏显示服务器名称",
@@ -361,8 +364,8 @@
"markAsWatched": "标记为已观看",
"markAsUnwatched": "标记为未观看",
"removeFromContinueWatching": "从继续观看中移除",
"viewDetails": "查看详情",
"goToSeries": "转到系列",
"goToSeason": "转到季",
"shufflePlay": "随机播放",
"shuffleNotAvailableOffline": "离线时无法随机播放",
"fileInfo": "文件信息",
@@ -508,7 +511,6 @@
"fileInfoNotAvailable": "文件信息不可用",
"errorLoadingFileInfo": "加载文件信息时出错: ${error}",
"errorLoadingSeries": "加载系列时出错",
"errorLoadingSeason": "加载季时出错",
"musicNotSupported": "尚不支持播放音乐",
"noDescriptionAvailable": "暂无描述",
"noProfilesAvailable": "没有可用的用户",
+11 -1
View File
@@ -99,8 +99,18 @@ MediaItem? firstUnwatchedEpisode(List<MediaItem> episodes) {
/// episode. With neither, fall back to the first season that still has
/// unwatched episodes (so a partially-watched show removed from Continue
/// Watching still opens on the right season), then [defaultPlaybackSeasonIndex].
int preferredSeasonIndex(List<MediaItem> seasons, {int? initialSeasonIndex, MediaItem? onDeckEpisode}) {
int preferredSeasonIndex(
List<MediaItem> seasons, {
String? initialSeasonId,
int? initialSeasonIndex,
MediaItem? onDeckEpisode,
}) {
if (seasons.isEmpty) return 0;
if (initialSeasonId != null) {
final idx = seasons.indexWhere((season) => season.kind == MediaKind.season && season.id == initialSeasonId);
if (idx != -1) return idx;
}
if (initialSeasonIndex != null) {
final idx = seasons.indexWhere((season) => season.kind == MediaKind.season && season.index == initialSeasonIndex);
if (idx != -1) return idx;
+4 -3
View File
@@ -59,6 +59,7 @@ import '../utils/app_logger.dart';
import '../utils/dialogs.dart';
import '../utils/formatters.dart';
import '../utils/media_hub_ordering.dart';
import '../utils/media_navigation_helper.dart';
import '../utils/provider_extensions.dart';
import '../utils/video_player_navigation.dart';
import '../utils/layout_constants.dart';
@@ -538,7 +539,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
},
onSelect: () {
if (_onDeck.isNotEmpty && _currentHeroIndex < _onDeck.length) {
navigateToVideoPlayer(context, metadata: _onDeck[_currentHeroIndex]);
navigateToMediaItem(context, _onDeck[_currentHeroIndex], playDirectly: true);
}
},
)(node, event);
@@ -1819,8 +1820,8 @@ class _DiscoverScreenState extends State<DiscoverScreen>
child: ClickableCursor(
child: GestureDetector(
onTap: () {
appLogger.d('Navigating to VideoPlayerScreen for: ${heroItem.title}');
navigateToVideoPlayer(context, metadata: heroItem);
appLogger.d('Activating hero item: ${heroItem.title}');
navigateToMediaItem(context, heroItem, playDirectly: true);
},
child: Stack(
fit: StackFit.expand,
+163 -16
View File
@@ -191,15 +191,36 @@ class MediaDetailScreen extends StatefulWidget {
/// If provided, auto-selects this season index when the screen loads.
/// Used when navigating to a show from a season context.
final int? initialSeasonIndex;
final String? initialSeasonId;
final String? initialEpisodeId;
const MediaDetailScreen({super.key, required this.metadata, this.isOffline = false, this.initialSeasonIndex});
const MediaDetailScreen({
super.key,
required this.metadata,
this.isOffline = false,
this.initialSeasonIndex,
this.initialSeasonId,
this.initialEpisodeId,
});
@override
State<MediaDetailScreen> createState() => _MediaDetailScreenState();
}
PageRoute<bool> mediaDetailRoute({required MediaItem metadata, bool isOffline = false, int? initialSeasonIndex}) {
final page = MediaDetailScreen(metadata: metadata, isOffline: isOffline, initialSeasonIndex: initialSeasonIndex);
PageRoute<bool> mediaDetailRoute({
required MediaItem metadata,
bool isOffline = false,
int? initialSeasonIndex,
String? initialSeasonId,
String? initialEpisodeId,
}) {
final page = MediaDetailScreen(
metadata: metadata,
isOffline: isOffline,
initialSeasonIndex: initialSeasonIndex,
initialSeasonId: initialSeasonId,
initialEpisodeId: initialEpisodeId,
);
if (!PlatformDetector.isTV()) return MaterialPageRoute<bool>(builder: (_) => page);
return PageRouteBuilder<bool>(
@@ -285,8 +306,12 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
final ScrollController _seasonTabsScrollController = ScrollController();
final FocusNode _firstEpisodeFocusNode = FocusNode(debugLabel: 'first_episode');
final FocusNode _lastEpisodeFocusNode = FocusNode(debugLabel: 'last_episode');
final FocusNode _initialEpisodeFocusNode = FocusNode(debugLabel: 'initial_episode');
String? _lastEpisodeFocusPinnedKey;
bool _suppressNextLastEpisodeFocusLoad = false;
bool _initialDetailFocusApplied = false;
bool _initialEpisodePagingInFlight = false;
bool _initialEpisodePagingDone = false;
static const int _episodesPageSize = 200;
// Sentinel at the end of the inline episode list; its viewport position drives
// lazy paging (the list is shrink-wrapped, so it can't self-detect near-end).
@@ -765,6 +790,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
_firstEpisodeFocusNode.dispose();
_lastEpisodeFocusNode.removeListener(_onLastEpisodeFocusChanged);
_lastEpisodeFocusNode.dispose();
_initialEpisodeFocusNode.dispose();
super.dispose();
}
@@ -1534,7 +1560,12 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
/// Find the season index matching the initial selection or on-deck episode,
/// then fall back to the same season the Play button would use.
int _findOnDeckSeasonIndex(List<MediaItem> seasons) {
return preferredSeasonIndex(seasons, initialSeasonIndex: widget.initialSeasonIndex, onDeckEpisode: _onDeckEpisode);
return preferredSeasonIndex(
seasons,
initialSeasonId: widget.initialSeasonId,
initialSeasonIndex: widget.initialSeasonIndex,
onDeckEpisode: _onDeckEpisode,
);
}
/// Fetch episodes for a specific season by index, using cache when available
@@ -1917,6 +1948,93 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
scrollContextToCenter(key.currentContext);
}
bool get _hasInitialDetailFocusTarget =>
widget.initialEpisodeId != null || widget.initialSeasonId != null || widget.initialSeasonIndex != null;
bool get _episodesContainInitialTarget {
final targetEpisodeId = widget.initialEpisodeId;
return targetEpisodeId != null && _episodes.any((episode) => episode.id == targetEpisodeId);
}
void _scheduleInitialMobileDetailFocus(MediaItem metadata) {
if (_initialDetailFocusApplied || PlatformDetector.isTV() || !_hasInitialDetailFocusTarget) return;
if (widget.initialEpisodeId != null) {
if (_episodesContainInitialTarget) {
_applyInitialMobileFocus(_initialTargetEpisodeFocusNode(), _seasonsSectionKey);
return;
}
_maybeLoadMoreForInitialEpisode();
// Target never materialized (stale/deleted id) — fall back to the
// season anchors below instead of retrying forever.
if (!_initialEpisodePagingDone) return;
}
if (metadata.isShow &&
!_showEpisodesDirectly &&
_seasons.isNotEmpty &&
_seasonTabFocusNodes.length > _selectedSeasonIndex) {
_applyInitialMobileFocus(_seasonTabFocusNodes[_selectedSeasonIndex], _seasonsSectionKey);
return;
}
if (((metadata.isShow && _showEpisodesDirectly) || metadata.isSeason) && _episodes.isNotEmpty) {
_applyInitialMobileFocus(_firstEpisodeFocusNode, _seasonsSectionKey);
}
}
void _applyInitialMobileFocus(FocusNode node, GlobalKey sectionKey) {
_initialDetailFocusApplied = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
node.requestFocus();
_scrollSectionIntoView(sectionKey);
});
}
void _maybeLoadMoreForInitialEpisode() {
if (_initialEpisodePagingDone || _initialEpisodePagingInFlight) return;
if (_episodesContainInitialTarget) {
_initialEpisodePagingDone = true;
return;
}
final hasMore = _isFlattenEpisodeList ? _allEpisodes.hasMore : _selectedSeasonHasMore;
final pageError = _isFlattenEpisodeList ? _allEpisodesPageError : _seasonEpisodesPageError;
if (!hasMore || pageError) {
// All pages loaded (or paging failed) without the target appearing.
_initialEpisodePagingDone = true;
return;
}
if (_isFlattenEpisodeList ? _isLoadingAllEpisodes : _isLoadingMoreSeasonEpisodes) return;
_initialEpisodePagingInFlight = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted || _episodesContainInitialTarget) {
_initialEpisodePagingInFlight = false;
return;
}
Future<void>? load;
if (_isFlattenEpisodeList) {
if (_allEpisodes.hasMore && !_isLoadingAllEpisodes && !_allEpisodesPageError) {
load = _loadMoreAllEpisodes();
}
} else if (_selectedSeasonHasMore && !_isLoadingMoreSeasonEpisodes && !_seasonEpisodesPageError) {
load = _loadMoreSeasonEpisodes();
}
if (load == null) {
_initialEpisodePagingInFlight = false;
return;
}
// The loaders setState on success and failure, so the resulting rebuild
// re-enters this method for the next page (or marks paging done).
unawaited(load.whenComplete(() => _initialEpisodePagingInFlight = false));
});
}
/// Focus the first available section above the primary action row.
void _focusAboveActionRow() {
if (PlatformDetector.isTV()) return;
@@ -2431,9 +2549,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
/// Build episode list directly when the library hides seasons for single-season shows
Widget _buildEpisodesList() {
final client = _getMediaClientForMetadata(context);
final pinnedLastEpisodeKey = _lastEpisodeFocusPinnedKey;
final hasPinnedLastEpisode =
pinnedLastEpisodeKey != null && _episodes.any((episode) => episode.globalKey == pinnedLastEpisodeKey);
final hasPinnedLastEpisode = _hasPinnedLastEpisodeInList;
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
@@ -2454,15 +2570,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
client: client,
isOffline: widget.isOffline,
autofocus: false,
focusNode: index == 0
? _firstEpisodeFocusNode
: _shouldUseLastEpisodeFocusNode(
episode: episode,
index: index,
hasPinnedLastEpisode: hasPinnedLastEpisode,
)
? _lastEpisodeFocusNode
: null,
focusNode: _episodeListFocusNode(episode: episode, index: index, hasPinnedLastEpisode: hasPinnedLastEpisode),
onNavigateUp: index == 0
? () {
if (!_showEpisodesDirectly) {
@@ -2510,6 +2618,39 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
return index == _episodes.length - 1;
}
bool get _hasPinnedLastEpisodeInList {
final pinnedKey = _lastEpisodeFocusPinnedKey;
return pinnedKey != null && _episodes.any((episode) => episode.globalKey == pinnedKey);
}
/// Resolve the focus node for an inline episode list item. Role nodes
/// (first/last) take priority so their consumers always find them attached;
/// the initial navigation target only claims a node when no role applies.
FocusNode? _episodeListFocusNode({
required MediaItem episode,
required int index,
required bool hasPinnedLastEpisode,
}) {
if (index == 0) return _firstEpisodeFocusNode;
if (_shouldUseLastEpisodeFocusNode(episode: episode, index: index, hasPinnedLastEpisode: hasPinnedLastEpisode)) {
return _lastEpisodeFocusNode;
}
if (widget.initialEpisodeId == episode.id) return _initialEpisodeFocusNode;
return null;
}
/// The node the initial target episode's card actually holds.
FocusNode _initialTargetEpisodeFocusNode() {
final index = _episodes.indexWhere((episode) => episode.id == widget.initialEpisodeId);
if (index == -1) return _initialEpisodeFocusNode;
return _episodeListFocusNode(
episode: _episodes[index],
index: index,
hasPinnedLastEpisode: _hasPinnedLastEpisodeInList,
) ??
_initialEpisodeFocusNode;
}
/// Tail of the inline episode list: a retry tile when a page failed, otherwise
/// a spinner. Carries [_episodeTailKey] so the scroll listener can detect when
/// it nears the viewport and page the next batch in.
@@ -2878,6 +3019,8 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
return _buildTvDetailScreen(context, metadata, _handleMediaDetailBackKey);
}
_scheduleInitialMobileDetailFocus(metadata);
final blockSystemBack = Platform.isAndroid && InputModeTracker.isKeyboardMode(context);
final content = PrimaryScrollController(
controller: _scrollController,
@@ -3115,6 +3258,9 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
) {
final size = MediaQuery.sizeOf(context);
final detailHubs = _tvDetailHubs(metadata);
if (widget.initialEpisodeId != null && !_initialEpisodePagingDone) {
_maybeLoadMoreForInitialEpisode();
}
final hideSpoilers = SettingsService.instance.read(SettingsService.hideSpoilers);
final detailScale = TvLayoutConstants.scaleForSize(size);
final spotlightTop = (size.height * 0.08).clamp(44.0 * detailScale, 110.0 * detailScale).toDouble();
@@ -3601,6 +3747,7 @@ class _MediaDetailScreenState extends State<MediaDetailScreen>
}
String? _tvDetailInitialItemId(MediaItem metadata) {
if (widget.initialEpisodeId != null) return widget.initialEpisodeId;
if (!metadata.isShow) return null;
return _onDeckEpisode?.id;
}
@@ -63,6 +63,7 @@ class AppearanceSettingsScreen extends StatelessWidget {
title: t.settings.showHeroSection,
subtitle: t.settings.showHeroSectionDescription,
),
_continueWatchingActionSelector(),
SettingSwitchTile(
pref: SettingsService.useGlobalHubs,
icon: Symbols.home_rounded,
@@ -252,6 +253,18 @@ class AppearanceSettingsScreen extends StatelessWidget {
encode: (v) => v,
);
Widget _continueWatchingActionSelector() => SettingSegmentedTile<ContinueWatchingAction, ContinueWatchingAction>(
pref: SettingsService.continueWatchingAction,
icon: Symbols.play_circle_rounded,
title: t.settings.continueWatchingAction,
segments: [
ButtonSegment(value: ContinueWatchingAction.play, label: Text(t.settings.continueWatchingPlay)),
ButtonSegment(value: ContinueWatchingAction.details, label: Text(t.settings.continueWatchingDetails)),
],
decode: (v) => v,
encode: (v) => v,
);
// Sections offered as a startup destination, in display order. Live TV is
// always listed; if no server provides it, startup falls back to Home.
static const _startupSectionOptions = [
+8
View File
@@ -35,6 +35,8 @@ enum ViewMode { grid, list }
enum EpisodePosterMode { seriesPoster, seasonPoster, episodeThumbnail }
enum ContinueWatchingAction { play, details }
enum SubAssOverride { no, yes, scale, force, strip }
enum DvConversionModePreference { auto, disabled, dv81, hevcStrip }
@@ -405,6 +407,11 @@ class SettingsService extends BaseSharedPreferencesService {
static const bufferSize = _BufferSizePref();
static const libraryDensity = _LibraryDensityPref();
static const episodePosterMode = _EpisodePosterModePref();
static const continueWatchingAction = EnumPref<ContinueWatchingAction>(
'continue_watching_action',
values: ContinueWatchingAction.values,
defaultValue: ContinueWatchingAction.play,
);
static const mpvConfigText = _MpvConfigTextPref();
static final keyboardShortcuts = JsonPref<Map<String, String>>(
@@ -701,6 +708,7 @@ class SettingsService extends BaseSharedPreferencesService {
preferredAudioCodec,
viewMode,
showHeroSection,
continueWatchingAction,
seekTimeSmall,
seekTimeLarge,
sleepTimerDuration,
+120 -35
View File
@@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import '../i18n/strings.g.dart';
import '../media/ids.dart';
import '../media/media_item.dart';
import '../media/media_item_types.dart';
import '../media/media_kind.dart';
import '../media/media_playlist.dart';
import '../screens/collection_detail_screen.dart';
import '../screens/main_screen.dart';
import '../screens/media_detail_screen.dart';
import '../screens/playlist/playlist_detail_screen.dart';
import '../services/settings_service.dart';
import '../utils/global_key_utils.dart';
import 'plex_library_section_helpers.dart';
import 'video_player_navigation.dart';
@@ -26,14 +29,98 @@ enum MediaNavigationResult {
librarySelected,
}
class MediaDetailNavigationTarget {
final MediaItem metadata;
final int? initialSeasonIndex;
final String? initialSeasonId;
final String? initialEpisodeId;
const MediaDetailNavigationTarget({
required this.metadata,
this.initialSeasonIndex,
this.initialSeasonId,
this.initialEpisodeId,
});
}
MediaDetailNavigationTarget mediaDetailNavigationTargetFor(MediaItem item, {MediaItem? metadataOverride}) {
if (item.isEpisode && item.grandparentId != null) {
return MediaDetailNavigationTarget(
metadata:
metadataOverride ??
MediaItem(
id: item.grandparentId!,
backend: item.backend,
kind: MediaKind.show,
title: item.grandparentTitle ?? item.displayTitle,
thumbPath: item.grandparentThumbPath,
artPath: item.grandparentArtPath,
libraryId: item.libraryId,
libraryTitle: item.libraryTitle,
serverId: item.serverId,
serverName: item.serverName,
),
initialSeasonIndex: item.parentIndex,
initialSeasonId: item.parentId,
initialEpisodeId: item.id,
);
}
if (item.isEpisode && item.parentId != null) {
return MediaDetailNavigationTarget(
metadata:
metadataOverride ??
MediaItem(
id: item.parentId!,
backend: item.backend,
kind: MediaKind.season,
title: item.parentTitle ?? t.common.seasonNumber(number: item.parentIndex ?? ''),
index: item.parentIndex,
thumbPath: item.parentThumbPath,
parentId: item.grandparentId,
libraryId: item.libraryId,
libraryTitle: item.libraryTitle,
serverId: item.serverId,
serverName: item.serverName,
),
initialEpisodeId: item.id,
);
}
if (item.isSeason && item.parentId != null) {
return MediaDetailNavigationTarget(
metadata:
metadataOverride ??
MediaItem(
id: item.parentId!,
backend: item.backend,
kind: MediaKind.show,
title: item.grandparentTitle ?? item.parentTitle ?? item.displayTitle,
thumbPath: item.grandparentThumbPath ?? item.parentThumbPath,
artPath: item.grandparentArtPath,
libraryId: item.libraryId,
libraryTitle: item.libraryTitle,
serverId: item.serverId,
serverName: item.serverName,
),
initialSeasonIndex: item.index,
initialSeasonId: item.id,
);
}
return MediaDetailNavigationTarget(metadata: metadataOverride ?? item);
}
/// Navigates to the appropriate screen based on the item type.
///
/// Accepts a [MediaItem] or a [MediaPlaylist] (typed as [Object] because Dart
/// has no nominal union type).
///
/// For episodes, starts playback directly via video player.
/// For movies, starts playback directly if [playDirectly] is true, otherwise
/// navigates to media detail screen.
/// For episodes, starts playback directly via video player unless [playDirectly]
/// is paired with the Continue Watching details setting.
/// For movies, starts playback directly if [playDirectly] is true and the
/// Continue Watching details setting is disabled; otherwise navigates to media
/// detail screen.
/// For seasons, navigates to season detail screen.
/// For playlists, navigates to playlist detail screen.
/// For collections, navigates to collection detail screen.
@@ -45,7 +132,9 @@ enum MediaNavigationResult {
///
/// Set [isOffline] to true for downloaded content without server access.
///
/// Set [playDirectly] to true to play movies immediately (e.g., from continue watching).
/// Set [playDirectly] to true for Continue Watching activation; the user's
/// Continue Watching action setting decides whether resumable movies/episodes
/// play immediately or open details first.
///
/// Returns a [MediaNavigationResult] indicating what action was taken:
/// - [MediaNavigationResult.navigated]: Navigation completed, item refresh handled
@@ -67,6 +156,10 @@ Future<MediaNavigationResult> navigateToMediaItem(
return MediaNavigationResult.unsupported;
}
final mi = item;
final shouldOpenContinueWatchingDetails =
playDirectly &&
(SettingsService.instanceOrNull?.read(SettingsService.continueWatchingAction) ?? ContinueWatchingAction.play) ==
ContinueWatchingAction.details;
// Handle library section items (shared whole-library entries) — Plex-only;
// [PlexLibrarySection.isLibrarySection] reads the stashed `key` from `raw`.
@@ -100,6 +193,9 @@ Future<MediaNavigationResult> navigateToMediaItem(
case MediaKind.clip:
case MediaKind.episode:
if (shouldOpenContinueWatchingDetails && mi.kind == MediaKind.episode) {
return navigateToMediaItemDetails(context, mi, onRefresh: onRefresh, isOffline: isOffline);
}
final result = await navigateToVideoPlayer(context, metadata: mi, isOffline: isOffline);
if (result == true && context.mounted) {
onRefresh?.call(mi.id);
@@ -107,52 +203,41 @@ Future<MediaNavigationResult> navigateToMediaItem(
return MediaNavigationResult.navigated;
case MediaKind.movie:
if (playDirectly) {
if (playDirectly && !shouldOpenContinueWatchingDetails) {
final result = await navigateToVideoPlayer(context, metadata: mi, isOffline: isOffline);
if (result == true && context.mounted) {
onRefresh?.call(mi.id);
}
return MediaNavigationResult.navigated;
}
return _showDetail(context, mi, isOffline, onRefresh);
return navigateToMediaItemDetails(context, mi, isOffline: isOffline, onRefresh: onRefresh);
case MediaKind.season:
if (mi.parentId != null) {
final showStub = MediaItem(
id: mi.parentId!,
backend: mi.backend,
kind: MediaKind.show,
title: mi.grandparentTitle ?? mi.parentTitle ?? mi.displayTitle,
thumbPath: mi.grandparentThumbPath ?? mi.parentThumbPath,
artPath: mi.grandparentArtPath,
libraryId: mi.libraryId,
libraryTitle: mi.libraryTitle,
serverId: mi.serverId,
serverName: mi.serverName,
);
final result = await Navigator.push<bool>(
context,
mediaDetailRoute(metadata: showStub, isOffline: isOffline, initialSeasonIndex: mi.index),
);
if (result == true && context.mounted) {
onRefresh?.call(mi.id);
}
return MediaNavigationResult.navigated;
}
return _showDetail(context, mi, isOffline, onRefresh);
return navigateToMediaItemDetails(context, mi, isOffline: isOffline, onRefresh: onRefresh);
default:
return _showDetail(context, mi, isOffline, onRefresh);
return navigateToMediaItemDetails(context, mi, isOffline: isOffline, onRefresh: onRefresh);
}
}
Future<MediaNavigationResult> _showDetail(
Future<MediaNavigationResult> navigateToMediaItemDetails(
BuildContext context,
MediaItem mi,
bool isOffline,
MediaItem mi, {
bool isOffline = false,
void Function(String)? onRefresh,
) async {
final result = await Navigator.push<bool>(context, mediaDetailRoute(metadata: mi, isOffline: isOffline));
MediaItem? metadataOverride,
}) async {
final target = mediaDetailNavigationTargetFor(mi, metadataOverride: metadataOverride);
final result = await Navigator.push<bool>(
context,
mediaDetailRoute(
metadata: target.metadata,
isOffline: isOffline,
initialSeasonIndex: target.initialSeasonIndex,
initialSeasonId: target.initialSeasonId,
initialEpisodeId: target.initialEpisodeId,
),
);
if (result == true && context.mounted) {
onRefresh?.call(mi.id);
}
+6 -82
View File
@@ -17,7 +17,6 @@ import '../providers/watch_state_store.dart';
import '../services/download_storage_service.dart';
import '../services/settings_service.dart';
import 'settings_builder.dart';
import '../screens/media_detail_screen.dart';
import '../utils/content_utils.dart';
import '../utils/provider_extensions.dart';
import '../utils/formatters.dart';
@@ -382,7 +381,7 @@ class MediaCardState extends State<MediaCard> with ContextMenuTapMixin<MediaCard
_ClickableText(
text: item.displayTitle,
style: const TextStyle(fontWeight: .w600, fontSize: 13, height: 1.1),
onTap: () => _navigateToDetail(context, item, isOffline: widget.isOffline),
onTap: () => _navigateToFocusedDetail(context, item, isOffline: widget.isOffline),
)
else
Text(
@@ -566,7 +565,7 @@ class _MediaCardList extends StatelessWidget {
_ClickableText(
text: 'S${mi.parentIndex}',
style: style,
onTap: () => _navigateToSeason(context, mi, isOffline: isOffline),
onTap: () => _navigateToFocusedDetail(context, mi, isOffline: isOffline),
),
Text('$episodeNum · ', style: style),
Expanded(
@@ -624,7 +623,7 @@ class _MediaCardList extends StatelessWidget {
_ClickableText(
text: (item as MediaItem).displayTitle,
style: TextStyle(fontWeight: .w600, fontSize: _titleFontSize, height: 1.2),
onTap: () => _navigateToDetail(context, item as MediaItem, isOffline: isOffline),
onTap: () => _navigateToFocusedDetail(context, item as MediaItem, isOffline: isOffline),
)
else
Text(
@@ -859,7 +858,7 @@ class _MediaCardHelpers {
_ClickableText(
text: 'S${mi.parentIndex}',
style: subtitleStyle,
onTap: () => _navigateToSeason(context, mi, isOffline: isOffline),
onTap: () => _navigateToFocusedDetail(context, mi, isOffline: isOffline),
),
Text('$episodeSuffix · ', style: subtitleStyle),
Expanded(
@@ -981,83 +980,8 @@ bool _hasClickableTitle(MediaItem mi) {
return false;
}
void _navigateToSeason(BuildContext context, MediaItem episode, {bool isOffline = false}) {
if (episode.grandparentId != null) {
final showStub = MediaItem(
id: episode.grandparentId!,
backend: episode.backend,
kind: MediaKind.show,
title: episode.grandparentTitle ?? episode.displayTitle,
thumbPath: episode.grandparentThumbPath,
artPath: episode.grandparentArtPath,
libraryId: episode.libraryId,
libraryTitle: episode.libraryTitle,
serverId: episode.serverId,
serverName: episode.serverName,
);
Navigator.push(
context,
mediaDetailRoute(metadata: showStub, isOffline: isOffline, initialSeasonIndex: episode.parentIndex),
);
} else if (episode.parentId != null) {
// Fallback: navigate to season directly if no grandparent
final seasonStub = MediaItem(
id: episode.parentId!,
backend: episode.backend,
kind: MediaKind.season,
title: episode.parentTitle ?? t.common.seasonNumber(number: episode.parentIndex ?? ''),
index: episode.parentIndex,
parentId: episode.grandparentId,
thumbPath: episode.parentThumbPath,
libraryId: episode.libraryId,
libraryTitle: episode.libraryTitle,
serverId: episode.serverId,
serverName: episode.serverName,
);
Navigator.push(context, mediaDetailRoute(metadata: seasonStub, isOffline: isOffline));
}
}
/// Navigate to the detail screen for a media item.
/// For episodes/seasons: navigates to the parent show with season pre-selected.
/// For movies and other types: navigates to the item's own detail page.
void _navigateToDetail(BuildContext context, MediaItem mi, {bool isOffline = false}) {
MediaItem target = mi;
int? initialSeasonIndex;
if (mi.isEpisode && mi.grandparentId != null) {
target = MediaItem(
id: mi.grandparentId!,
backend: mi.backend,
kind: MediaKind.show,
title: mi.grandparentTitle ?? mi.displayTitle,
thumbPath: mi.grandparentThumbPath,
artPath: mi.grandparentArtPath,
libraryId: mi.libraryId,
libraryTitle: mi.libraryTitle,
serverId: mi.serverId,
serverName: mi.serverName,
);
} else if (mi.isSeason && mi.parentId != null) {
initialSeasonIndex = mi.index;
target = MediaItem(
id: mi.parentId!,
backend: mi.backend,
kind: MediaKind.show,
title: mi.grandparentTitle ?? mi.parentTitle ?? mi.displayTitle,
thumbPath: mi.grandparentThumbPath ?? mi.parentThumbPath,
artPath: mi.grandparentArtPath,
libraryId: mi.libraryId,
libraryTitle: mi.libraryTitle,
serverId: mi.serverId,
serverName: mi.serverName,
);
}
Navigator.push(
context,
mediaDetailRoute(metadata: target, isOffline: isOffline, initialSeasonIndex: initialSeasonIndex),
);
void _navigateToFocusedDetail(BuildContext context, MediaItem item, {bool isOffline = false}) {
navigateToMediaItemDetails(context, item, isOffline: isOffline);
}
/// Text widget that shows hover underline + pointer cursor only in pointer mode.
+26 -27
View File
@@ -9,6 +9,7 @@ import 'package:provider/provider.dart';
import '../providers/watch_state_store.dart';
import '../media/media_backend.dart';
import '../media/media_item.dart';
import '../media/media_item_types.dart';
import '../media/media_kind.dart';
import '../media/media_playlist.dart';
import '../media/media_server_client.dart';
@@ -35,6 +36,7 @@ import '../profiles/profile.dart';
import '../utils/provider_extensions.dart';
import '../utils/app_logger.dart';
import '../utils/library_refresh_notifier.dart';
import '../utils/media_navigation_helper.dart';
import '../utils/media_server_http_client.dart';
import '../utils/platform_detector.dart';
import '../utils/snackbar_helper.dart';
@@ -311,10 +313,13 @@ class MediaContextMenuState extends State<MediaContextMenu> {
);
}
if (mediaKind == MediaKind.movie ||
mediaKind == MediaKind.show ||
mediaKind == MediaKind.season ||
mediaKind == MediaKind.episode) {
final isVideoKind = mediaItem.isVideoContent;
if (widget.isInContinueWatching && isVideoKind) {
menuActions.add(_MenuAction(value: 'details', icon: Symbols.info_rounded, label: t.mediaMenu.viewDetails));
}
if (isVideoKind) {
menuActions.add(_MenuAction(value: 'rate', icon: Symbols.star_rounded, label: t.mediaMenu.rate));
}
@@ -363,19 +368,11 @@ class MediaContextMenuState extends State<MediaContextMenu> {
final itemSeriesKey = mediaKind == MediaKind.episode ? mediaItem.grandparentId : mediaItem.parentId;
if ((mediaKind == MediaKind.episode || mediaKind == MediaKind.season) &&
itemSeriesKey != null &&
!widget.isInContinueWatching &&
ancestorSeriesKey != itemSeriesKey) {
menuActions.add(_MenuAction(value: 'series', icon: Symbols.tv_rounded, label: t.mediaMenu.goToSeries));
}
// Go to Season (for episodes) — hide if already viewing that season's MediaDetailScreen
if (mediaKind == MediaKind.episode &&
mediaItem.parentTitle != null &&
!(ancestorMeta != null && ancestorMeta.kind == MediaKind.season && ancestorMeta.id == mediaItem.parentId)) {
menuActions.add(
_MenuAction(value: 'season', icon: Symbols.playlist_play_rounded, label: t.mediaMenu.goToSeason),
);
}
if (mediaKind == MediaKind.show || mediaKind == MediaKind.season) {
menuActions.add(
_MenuAction(value: 'shuffle_play', icon: Symbols.shuffle_rounded, label: t.mediaMenu.shufflePlay),
@@ -615,6 +612,13 @@ class MediaContextMenuState extends State<MediaContextMenu> {
}
break;
case 'details':
didNavigate = true;
if (context.mounted) {
await navigateToMediaItemDetails(context, mediaItem!, onRefresh: _notifyRefresh);
}
break;
case 'rate':
if (context.mounted) {
try {
@@ -659,24 +663,19 @@ class MediaContextMenuState extends State<MediaContextMenu> {
await _navigateToRelated(
context,
mediaItem!.kind == MediaKind.season ? mediaItem.parentId : mediaItem.grandparentId,
(item) => mediaDetailRoute(metadata: item),
(item) {
final target = mediaDetailNavigationTargetFor(mediaItem, metadataOverride: item);
return mediaDetailRoute(
metadata: target.metadata,
initialSeasonIndex: target.initialSeasonIndex,
initialSeasonId: target.initialSeasonId,
initialEpisodeId: target.initialEpisodeId,
);
},
t.messages.errorLoadingSeries,
);
break;
case 'season':
didNavigate = true;
// Navigate to the show with the season tab pre-selected
final seasonParentKey = mediaItem!.kind == MediaKind.episode ? mediaItem.grandparentId : mediaItem.parentId;
final seasonIndex = mediaItem.parentIndex;
await _navigateToRelated(
context,
seasonParentKey,
(show) => mediaDetailRoute(metadata: show, initialSeasonIndex: seasonIndex),
t.messages.errorLoadingSeason,
);
break;
case 'play_version':
didNavigate = await _handlePlayVersion(context);
break;
+95 -2
View File
@@ -566,7 +566,14 @@ void main() {
serverName: show.serverName,
);
Future<void> pumpPhoneDetail(WidgetTester tester, _FakeMediaServerClient client, MediaItem show) async {
Future<void> pumpPhoneDetail(
WidgetTester tester,
_FakeMediaServerClient client,
MediaItem show, {
String? initialSeasonId,
int? initialSeasonIndex,
String? initialEpisodeId,
}) async {
TvDetectionService.debugSetAppleTVOverride(false);
await SettingsService.getInstance();
tester.view.physicalSize = const Size(1100, 2400);
@@ -604,7 +611,12 @@ void main() {
],
child: MaterialApp(
theme: monoTheme(dark: true),
home: MediaDetailScreen(metadata: show),
home: MediaDetailScreen(
metadata: show,
initialSeasonId: initialSeasonId,
initialSeasonIndex: initialSeasonIndex,
initialEpisodeId: initialEpisodeId,
),
),
),
),
@@ -637,6 +649,87 @@ void main() {
await tester.pump(const Duration(milliseconds: 100));
}
testWidgets('phone detail focuses requested season tab', (tester) async {
final show = buildShow();
final season1 = buildSeason(show, 1);
final season2 = buildSeason(show, 2);
final client = _FakeMediaServerClient(
show: show,
childrenByParent: {
show.id: [season1, season2],
season1.id: [buildEpisode(show, season1, 1)],
season2.id: [buildEpisode(show, season2, 1)],
},
);
await pumpPhoneDetail(tester, client, show, initialSeasonId: season2.id);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('Episode S2E1'), findsOneWidget);
expect(FocusManager.instance.primaryFocus?.debugLabel, 'season_tab_1');
});
testWidgets('phone detail focuses requested episode row', (tester) async {
final show = buildShow();
final season1 = buildSeason(show, 1);
final season2 = buildSeason(show, 2);
final episode2 = buildEpisode(show, season2, 2);
final client = _FakeMediaServerClient(
show: show,
childrenByParent: {
show.id: [season1, season2],
season1.id: [buildEpisode(show, season1, 1)],
season2.id: [buildEpisode(show, season2, 1), episode2, buildEpisode(show, season2, 3)],
},
);
await pumpPhoneDetail(
tester,
client,
show,
initialSeasonId: season2.id,
initialSeasonIndex: season2.index,
initialEpisodeId: episode2.id,
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('Episode S2E2'), findsOneWidget);
expect(FocusManager.instance.primaryFocus?.debugLabel, 'initial_episode');
});
testWidgets('phone detail keeps the first-episode role node when it is the target', (tester) async {
final show = buildShow();
final season1 = buildSeason(show, 1);
final season2 = buildSeason(show, 2);
final episode1 = buildEpisode(show, season2, 1);
final client = _FakeMediaServerClient(
show: show,
childrenByParent: {
show.id: [season1, season2],
season1.id: [buildEpisode(show, season1, 1)],
season2.id: [episode1, buildEpisode(show, season2, 2), buildEpisode(show, season2, 3)],
},
);
await pumpPhoneDetail(
tester,
client,
show,
initialSeasonId: season2.id,
initialSeasonIndex: season2.index,
initialEpisodeId: episode1.id,
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
// The first row keeps _firstEpisodeFocusNode (so season-tab DOWN keeps
// working) and the initial focus lands on that node instead.
expect(find.text('Episode S2E1'), findsOneWidget);
expect(FocusManager.instance.primaryFocus?.debugLabel, 'first_episode');
});
testWidgets('marking the show watched flips every visible episode row', (tester) async {
final show = buildShow();
final season1 = buildSeason(show, 1);
+1
View File
@@ -92,6 +92,7 @@ void main() {
final season1 = _season('season-1');
final season2 = _season('season-2', index: 2);
expect(preferredSeasonIndex([special, season1, season2], initialSeasonId: season2.id, initialSeasonIndex: 1), 2);
expect(preferredSeasonIndex([special, season1, season2], initialSeasonIndex: 2), 2);
expect(
preferredSeasonIndex([special, season1, season2], onDeckEpisode: _episode('episode-2', parentId: season2.id)),
@@ -0,0 +1,60 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/media/media_backend.dart';
import 'package:plezy/media/media_item.dart';
import 'package:plezy/media/media_kind.dart';
import 'package:plezy/utils/media_navigation_helper.dart';
void main() {
test('episode detail target opens parent show and focuses season episode', () {
final episode = MediaItem(
id: 'episode-1',
backend: MediaBackend.plex,
kind: MediaKind.episode,
title: 'Episode 1',
parentId: 'season-2',
parentIndex: 2,
grandparentId: 'show-1',
grandparentTitle: 'The Show',
serverId: 'server-1',
);
final target = mediaDetailNavigationTargetFor(episode);
expect(target.metadata.id, 'show-1');
expect(target.metadata.kind, MediaKind.show);
expect(target.initialSeasonId, 'season-2');
expect(target.initialSeasonIndex, 2);
expect(target.initialEpisodeId, 'episode-1');
});
test('season detail target opens parent show and focuses season', () {
final season = MediaItem(
id: 'season-3',
backend: MediaBackend.jellyfin,
kind: MediaKind.season,
title: 'Season 3',
index: 3,
parentId: 'show-1',
parentTitle: 'The Show',
serverId: 'server-1',
);
final target = mediaDetailNavigationTargetFor(season);
expect(target.metadata.id, 'show-1');
expect(target.metadata.kind, MediaKind.show);
expect(target.initialSeasonId, 'season-3');
expect(target.initialSeasonIndex, 3);
expect(target.initialEpisodeId, isNull);
});
test('movie detail target keeps the movie itself', () {
final movie = MediaItem(id: 'movie-1', backend: MediaBackend.plex, kind: MediaKind.movie, title: 'Movie');
final target = mediaDetailNavigationTargetFor(movie);
expect(target.metadata, same(movie));
expect(target.initialSeasonId, isNull);
expect(target.initialEpisodeId, isNull);
});
}