feat: screen lock

close #286
This commit is contained in:
edde746
2026-03-22 11:48:34 +01:00
parent 2f5b596fff
commit 3ae2488adf
34 changed files with 318 additions and 32 deletions
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Forlad fuldskærm",
"alwaysOnTopButton": "Altid øverst",
"rotationLockButton": "Rotationslås",
"lockScreen": "Lås skærm",
"unlockScreen": "Lås skærm op",
"screenLockButton": "Skærmlås",
"longPressToUnlock": "Langt tryk for at låse op",
"timelineSlider": "Videotidslinje",
"volumeSlider": "Lydstyrkeniveau",
"endsAt": "Slutter kl. ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Vollbild verlassen",
"alwaysOnTopButton": "Immer im Vordergrund",
"rotationLockButton": "Dreh­sperre",
"lockScreen": "Bildschirm sperren",
"unlockScreen": "Bildschirm entsperren",
"screenLockButton": "Bildschirmsperre",
"longPressToUnlock": "Lange drücken zum Entsperren",
"timelineSlider": "Video-Zeitleiste",
"volumeSlider": "Lautstärkepegel",
"endsAt": "Endet um ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Exit fullscreen",
"alwaysOnTopButton": "Always on top",
"rotationLockButton": "Rotation lock",
"lockScreen": "Lock screen",
"unlockScreen": "Unlock screen",
"screenLockButton": "Screen lock",
"longPressToUnlock": "Long press to unlock",
"timelineSlider": "Video timeline",
"volumeSlider": "Volume level",
"endsAt": "Ends at ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Salir de pantalla completa",
"alwaysOnTopButton": "Siempre visible",
"rotationLockButton": "Bloqueo de rotación",
"lockScreen": "Bloquear pantalla",
"unlockScreen": "Desbloquear pantalla",
"screenLockButton": "Bloqueo de pantalla",
"longPressToUnlock": "Mantén pulsado para desbloquear",
"timelineSlider": "Línea de tiempo del video",
"volumeSlider": "Nivel de volumen",
"endsAt": "Termina a las ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Quitter le mode plein écran",
"alwaysOnTopButton": "Toujours au premier plan",
"rotationLockButton": "Verrouillage de rotation",
"lockScreen": "Verrouiller l'écran",
"unlockScreen": "Déverrouiller l'écran",
"screenLockButton": "Verrouillage de l'écran",
"longPressToUnlock": "Appui long pour déverrouiller",
"timelineSlider": "Timeline vidéo",
"volumeSlider": "Niveau sonore",
"endsAt": "Fin à ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Esci da schermo intero",
"alwaysOnTopButton": "Sempre in primo piano",
"rotationLockButton": "Blocco rotazione",
"lockScreen": "Blocca schermo",
"unlockScreen": "Sblocca schermo",
"screenLockButton": "Blocco schermo",
"longPressToUnlock": "Premi a lungo per sbloccare",
"timelineSlider": "Timeline video",
"volumeSlider": "Livello volume",
"endsAt": "Finisce alle ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "フルスクリーンを終了",
"alwaysOnTopButton": "常に前面に表示",
"rotationLockButton": "回転ロック",
"lockScreen": "画面をロック",
"unlockScreen": "画面のロックを解除",
"screenLockButton": "画面ロック",
"longPressToUnlock": "長押しでロック解除",
"timelineSlider": "動画タイムライン",
"volumeSlider": "音量レベル",
"endsAt": "${time}に終了",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "전체화면 종료",
"alwaysOnTopButton": "창 최상위 고정",
"rotationLockButton": "회전 잠금",
"lockScreen": "화면 잠금",
"unlockScreen": "화면 잠금 해제",
"screenLockButton": "화면 잠금",
"longPressToUnlock": "길게 눌러 잠금 해제",
"timelineSlider": "타임라인",
"volumeSlider": "볼륨 조절",
"endsAt": "${time}에 종료",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Avslutt fullskjerm",
"alwaysOnTopButton": "Alltid øverst",
"rotationLockButton": "Rotasjonslås",
"lockScreen": "Lås skjerm",
"unlockScreen": "Lås opp skjerm",
"screenLockButton": "Skjermlås",
"longPressToUnlock": "Langt trykk for å låse opp",
"timelineSlider": "Videotidslinje",
"volumeSlider": "Volumnivå",
"endsAt": "Slutter kl. ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Volledig scherm verlaten",
"alwaysOnTopButton": "Altijd bovenop",
"rotationLockButton": "Rotatievergrendeling",
"lockScreen": "Vergrendel scherm",
"unlockScreen": "Ontgrendel scherm",
"screenLockButton": "Schermvergrendeling",
"longPressToUnlock": "Lang indrukken om te ontgrendelen",
"timelineSlider": "Videotijdlijn",
"volumeSlider": "Volumeniveau",
"endsAt": "Eindigt om ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Wyjdź z pełnego ekranu",
"alwaysOnTopButton": "Zawsze na wierzchu",
"rotationLockButton": "Blokada obrotu",
"lockScreen": "Zablokuj ekran",
"unlockScreen": "Odblokuj ekran",
"screenLockButton": "Blokada ekranu",
"longPressToUnlock": "Przytrzymaj, aby odblokować",
"timelineSlider": "Oś czasu wideo",
"volumeSlider": "Poziom głośności",
"endsAt": "Kończy się o ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Sair da tela cheia",
"alwaysOnTopButton": "Sempre no topo",
"rotationLockButton": "Travar rotação",
"lockScreen": "Travar tela",
"unlockScreen": "Destravar tela",
"screenLockButton": "Travar tela",
"longPressToUnlock": "Pressione e segure para destravar",
"timelineSlider": "Linha do tempo do vídeo",
"volumeSlider": "Nível de volume",
"endsAt": "Termina às ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Выйти из полноэкранного режима",
"alwaysOnTopButton": "Всегда поверх",
"rotationLockButton": "Блокировка поворота",
"lockScreen": "Заблокировать экран",
"unlockScreen": "Разблокировать экран",
"screenLockButton": "Блокировка экрана",
"longPressToUnlock": "Удерживайте для разблокировки",
"timelineSlider": "Временная шкала",
"volumeSlider": "Уровень громкости",
"endsAt": "Закончится в ${time}",
+2 -2
View File
@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 15
/// Strings: 11910 (794 per locale)
/// Strings: 11970 (798 per locale)
///
/// Built on 2026-03-22 at 08:19 UTC
/// Built on 2026-03-22 at 10:44 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsDa implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Forlad fuldskærm';
@override String get alwaysOnTopButton => 'Altid øverst';
@override String get rotationLockButton => 'Rotationslås';
@override String get lockScreen => 'Lås skærm';
@override String get unlockScreen => 'Lås skærm op';
@override String get screenLockButton => 'Skærmlås';
@override String get longPressToUnlock => 'Langt tryk for at låse op';
@override String get timelineSlider => 'Videotidslinje';
@override String get volumeSlider => 'Lydstyrkeniveau';
@override String endsAt({required Object time}) => 'Slutter kl. ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsDa {
'videoControls.exitFullscreenButton' => 'Forlad fuldskærm',
'videoControls.alwaysOnTopButton' => 'Altid øverst',
'videoControls.rotationLockButton' => 'Rotationslås',
'videoControls.lockScreen' => 'Lås skærm',
'videoControls.unlockScreen' => 'Lås skærm op',
'videoControls.screenLockButton' => 'Skærmlås',
'videoControls.longPressToUnlock' => 'Langt tryk for at låse op',
'videoControls.timelineSlider' => 'Videotidslinje',
'videoControls.volumeSlider' => 'Lydstyrkeniveau',
'videoControls.endsAt' => ({required Object time}) => 'Slutter kl. ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsDa {
'liveTv.lateNight' => 'Sen aften',
'liveTv.whatsOn' => 'Hvad der kører',
'liveTv.watchChannel' => 'Se kanal',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoritter',
'collections.title' => 'Samlinger',
'collections.collection' => 'Samling',
'collections.empty' => 'Samlingen er tom',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Kan ikke slette: Ukendt bibliotekssektion',
'collections.deleteCollection' => 'Slet samling',
'collections.deleteConfirm' => ({required Object title}) => 'Er du sikker på, at du vil slette "${title}"? Denne handling kan ikke fortrydes.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsDe implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Vollbild verlassen';
@override String get alwaysOnTopButton => 'Immer im Vordergrund';
@override String get rotationLockButton => 'Dreh­sperre';
@override String get lockScreen => 'Bildschirm sperren';
@override String get unlockScreen => 'Bildschirm entsperren';
@override String get screenLockButton => 'Bildschirmsperre';
@override String get longPressToUnlock => 'Lange drücken zum Entsperren';
@override String get timelineSlider => 'Video-Zeitleiste';
@override String get volumeSlider => 'Lautstärkepegel';
@override String endsAt({required Object time}) => 'Endet um ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsDe {
'videoControls.exitFullscreenButton' => 'Vollbild verlassen',
'videoControls.alwaysOnTopButton' => 'Immer im Vordergrund',
'videoControls.rotationLockButton' => 'Dreh­sperre',
'videoControls.lockScreen' => 'Bildschirm sperren',
'videoControls.unlockScreen' => 'Bildschirm entsperren',
'videoControls.screenLockButton' => 'Bildschirmsperre',
'videoControls.longPressToUnlock' => 'Lange drücken zum Entsperren',
'videoControls.timelineSlider' => 'Video-Zeitleiste',
'videoControls.volumeSlider' => 'Lautstärkepegel',
'videoControls.endsAt' => ({required Object time}) => 'Endet um ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsDe {
'liveTv.lateNight' => 'Spätnacht',
'liveTv.whatsOn' => 'Jetzt im TV',
'liveTv.watchChannel' => 'Kanal ansehen',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoriten',
'downloads.title' => 'Downloads',
'downloads.manage' => 'Verwalten',
'downloads.tvShows' => 'Serien',
_ => null,
} ?? switch (path) {
'downloads.movies' => 'Filme',
'downloads.noDownloads' => 'Noch keine Downloads',
'downloads.noDownloadsDescription' => 'Heruntergeladene Inhalte werden hier für die Offline-Wiedergabe angezeigt',
+18 -2
View File
@@ -1100,6 +1100,18 @@ class TranslationsVideoControlsEn {
/// en: 'Rotation lock'
String get rotationLockButton => 'Rotation lock';
/// en: 'Lock screen'
String get lockScreen => 'Lock screen';
/// en: 'Unlock screen'
String get unlockScreen => 'Unlock screen';
/// en: 'Screen lock'
String get screenLockButton => 'Screen lock';
/// en: 'Long press to unlock'
String get longPressToUnlock => 'Long press to unlock';
/// en: 'Video timeline'
String get timelineSlider => 'Video timeline';
@@ -3196,6 +3208,10 @@ extension on Translations {
'videoControls.exitFullscreenButton' => 'Exit fullscreen',
'videoControls.alwaysOnTopButton' => 'Always on top',
'videoControls.rotationLockButton' => 'Rotation lock',
'videoControls.lockScreen' => 'Lock screen',
'videoControls.unlockScreen' => 'Unlock screen',
'videoControls.screenLockButton' => 'Screen lock',
'videoControls.longPressToUnlock' => 'Long press to unlock',
'videoControls.timelineSlider' => 'Video timeline',
'videoControls.volumeSlider' => 'Volume level',
'videoControls.endsAt' => ({required Object time}) => 'Ends at ${time}',
@@ -3384,12 +3400,12 @@ extension on Translations {
'liveTv.lateNight' => 'Late Night',
'liveTv.whatsOn' => 'What\'s On',
'liveTv.watchChannel' => 'Watch Channel',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favorites',
'collections.title' => 'Collections',
'collections.collection' => 'Collection',
'collections.empty' => 'Collection is empty',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Cannot delete: Unknown library section',
'collections.deleteCollection' => 'Delete Collection',
'collections.deleteConfirm' => ({required Object title}) => 'Are you sure you want to delete "${title}"? This action cannot be undone.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsEs implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Salir de pantalla completa';
@override String get alwaysOnTopButton => 'Siempre visible';
@override String get rotationLockButton => 'Bloqueo de rotación';
@override String get lockScreen => 'Bloquear pantalla';
@override String get unlockScreen => 'Desbloquear pantalla';
@override String get screenLockButton => 'Bloqueo de pantalla';
@override String get longPressToUnlock => 'Mantén pulsado para desbloquear';
@override String get timelineSlider => 'Línea de tiempo del video';
@override String get volumeSlider => 'Nivel de volumen';
@override String endsAt({required Object time}) => 'Termina a las ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsEs {
'videoControls.exitFullscreenButton' => 'Salir de pantalla completa',
'videoControls.alwaysOnTopButton' => 'Siempre visible',
'videoControls.rotationLockButton' => 'Bloqueo de rotación',
'videoControls.lockScreen' => 'Bloquear pantalla',
'videoControls.unlockScreen' => 'Desbloquear pantalla',
'videoControls.screenLockButton' => 'Bloqueo de pantalla',
'videoControls.longPressToUnlock' => 'Mantén pulsado para desbloquear',
'videoControls.timelineSlider' => 'Línea de tiempo del video',
'videoControls.volumeSlider' => 'Nivel de volumen',
'videoControls.endsAt' => ({required Object time}) => 'Termina a las ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsEs {
'liveTv.lateNight' => 'Trasnoche',
'liveTv.whatsOn' => 'En emisión',
'liveTv.watchChannel' => 'Ver canal',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoritos',
'collections.title' => 'Colecciones',
'collections.collection' => 'Colección',
'collections.empty' => 'La colección está vacía',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'No se puede eliminar: Sección de biblioteca desconocida',
'collections.deleteCollection' => 'Eliminar Colección',
'collections.deleteConfirm' => ({required Object title}) => '¿Estás seguro de que quieres eliminar "${title}"? Esta acción no se puede deshacer.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsFr implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Quitter le mode plein écran';
@override String get alwaysOnTopButton => 'Toujours au premier plan';
@override String get rotationLockButton => 'Verrouillage de rotation';
@override String get lockScreen => 'Verrouiller l\'écran';
@override String get unlockScreen => 'Déverrouiller l\'écran';
@override String get screenLockButton => 'Verrouillage de l\'écran';
@override String get longPressToUnlock => 'Appui long pour déverrouiller';
@override String get timelineSlider => 'Timeline vidéo';
@override String get volumeSlider => 'Niveau sonore';
@override String endsAt({required Object time}) => 'Fin à ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsFr {
'videoControls.exitFullscreenButton' => 'Quitter le mode plein écran',
'videoControls.alwaysOnTopButton' => 'Toujours au premier plan',
'videoControls.rotationLockButton' => 'Verrouillage de rotation',
'videoControls.lockScreen' => 'Verrouiller l\'écran',
'videoControls.unlockScreen' => 'Déverrouiller l\'écran',
'videoControls.screenLockButton' => 'Verrouillage de l\'écran',
'videoControls.longPressToUnlock' => 'Appui long pour déverrouiller',
'videoControls.timelineSlider' => 'Timeline vidéo',
'videoControls.volumeSlider' => 'Niveau sonore',
'videoControls.endsAt' => ({required Object time}) => 'Fin à ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsFr {
'liveTv.lateNight' => 'Nuit tardive',
'liveTv.whatsOn' => 'En ce moment',
'liveTv.watchChannel' => 'Regarder la chaîne',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoris',
'collections.title' => 'Collections',
'collections.collection' => 'Collection',
'collections.empty' => 'La collection est vide',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Impossible de supprimer : section de bibliothèque inconnue',
'collections.deleteCollection' => 'Supprimer la collection',
'collections.deleteConfirm' => ({required Object title}) => 'Êtes-vous sûr de vouloir supprimer "${title}" ? Cette action ne peut pas être annulée.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsIt implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Esci da schermo intero';
@override String get alwaysOnTopButton => 'Sempre in primo piano';
@override String get rotationLockButton => 'Blocco rotazione';
@override String get lockScreen => 'Blocca schermo';
@override String get unlockScreen => 'Sblocca schermo';
@override String get screenLockButton => 'Blocco schermo';
@override String get longPressToUnlock => 'Premi a lungo per sbloccare';
@override String get timelineSlider => 'Timeline video';
@override String get volumeSlider => 'Livello volume';
@override String endsAt({required Object time}) => 'Finisce alle ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsIt {
'videoControls.exitFullscreenButton' => 'Esci da schermo intero',
'videoControls.alwaysOnTopButton' => 'Sempre in primo piano',
'videoControls.rotationLockButton' => 'Blocco rotazione',
'videoControls.lockScreen' => 'Blocca schermo',
'videoControls.unlockScreen' => 'Sblocca schermo',
'videoControls.screenLockButton' => 'Blocco schermo',
'videoControls.longPressToUnlock' => 'Premi a lungo per sbloccare',
'videoControls.timelineSlider' => 'Timeline video',
'videoControls.volumeSlider' => 'Livello volume',
'videoControls.endsAt' => ({required Object time}) => 'Finisce alle ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsIt {
'liveTv.lateNight' => 'Notte tarda',
'liveTv.whatsOn' => 'In onda ora',
'liveTv.watchChannel' => 'Guarda canale',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Preferiti',
'downloads.title' => 'Download',
'downloads.manage' => 'Gestisci',
'downloads.tvShows' => 'Serie TV',
_ => null,
} ?? switch (path) {
'downloads.movies' => 'Film',
'downloads.noDownloads' => 'Nessun download',
'downloads.noDownloadsDescription' => 'I contenuti scaricati appariranno qui per la visualizzazione offline',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsJa implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'フルスクリーンを終了';
@override String get alwaysOnTopButton => '常に前面に表示';
@override String get rotationLockButton => '回転ロック';
@override String get lockScreen => '画面をロック';
@override String get unlockScreen => '画面のロックを解除';
@override String get screenLockButton => '画面ロック';
@override String get longPressToUnlock => '長押しでロック解除';
@override String get timelineSlider => '動画タイムライン';
@override String get volumeSlider => '音量レベル';
@override String endsAt({required Object time}) => '${time}に終了';
@@ -1601,6 +1605,10 @@ extension on TranslationsJa {
'videoControls.exitFullscreenButton' => 'フルスクリーンを終了',
'videoControls.alwaysOnTopButton' => '常に前面に表示',
'videoControls.rotationLockButton' => '回転ロック',
'videoControls.lockScreen' => '画面をロック',
'videoControls.unlockScreen' => '画面のロックを解除',
'videoControls.screenLockButton' => '画面ロック',
'videoControls.longPressToUnlock' => '長押しでロック解除',
'videoControls.timelineSlider' => '動画タイムライン',
'videoControls.volumeSlider' => '音量レベル',
'videoControls.endsAt' => ({required Object time}) => '${time}に終了',
@@ -1789,12 +1797,12 @@ extension on TranslationsJa {
'liveTv.lateNight' => '深夜',
'liveTv.whatsOn' => '放送中',
'liveTv.watchChannel' => 'チャンネルを視聴',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'お気に入り',
'collections.title' => 'コレクション',
'collections.collection' => 'コレクション',
'collections.empty' => 'コレクションは空です',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => '削除できません:不明なライブラリセクション',
'collections.deleteCollection' => 'コレクションを削除',
'collections.deleteConfirm' => ({required Object title}) => '"${title}"を削除してもよろしいですか?この操作は元に戻せません。',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsKo implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => '전체화면 종료';
@override String get alwaysOnTopButton => '창 최상위 고정';
@override String get rotationLockButton => '회전 잠금';
@override String get lockScreen => '화면 잠금';
@override String get unlockScreen => '화면 잠금 해제';
@override String get screenLockButton => '화면 잠금';
@override String get longPressToUnlock => '길게 눌러 잠금 해제';
@override String get timelineSlider => '타임라인';
@override String get volumeSlider => '볼륨 조절';
@override String endsAt({required Object time}) => '${time}에 종료';
@@ -1601,6 +1605,10 @@ extension on TranslationsKo {
'videoControls.exitFullscreenButton' => '전체화면 종료',
'videoControls.alwaysOnTopButton' => '창 최상위 고정',
'videoControls.rotationLockButton' => '회전 잠금',
'videoControls.lockScreen' => '화면 잠금',
'videoControls.unlockScreen' => '화면 잠금 해제',
'videoControls.screenLockButton' => '화면 잠금',
'videoControls.longPressToUnlock' => '길게 눌러 잠금 해제',
'videoControls.timelineSlider' => '타임라인',
'videoControls.volumeSlider' => '볼륨 조절',
'videoControls.endsAt' => ({required Object time}) => '${time}에 종료',
@@ -1789,12 +1797,12 @@ extension on TranslationsKo {
'liveTv.lateNight' => '심야 방송',
'liveTv.whatsOn' => '지금 방송 중',
'liveTv.watchChannel' => '채널 시청',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => '즐겨찾기',
'collections.title' => '컬렉션',
'collections.collection' => '컬렉션',
'collections.empty' => '컬렉션이 비어 있습니다',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => '삭제할 수 없습니다: 알 수 없는 미디어 라이브러리 섹션입니다',
'collections.deleteCollection' => '컬렉션 삭제',
'collections.deleteConfirm' => ({required Object title}) => '"${title}"을(를) 삭제 하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsNb implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Avslutt fullskjerm';
@override String get alwaysOnTopButton => 'Alltid øverst';
@override String get rotationLockButton => 'Rotasjonslås';
@override String get lockScreen => 'Lås skjerm';
@override String get unlockScreen => 'Lås opp skjerm';
@override String get screenLockButton => 'Skjermlås';
@override String get longPressToUnlock => 'Langt trykk for å låse opp';
@override String get timelineSlider => 'Videotidslinje';
@override String get volumeSlider => 'Volumnivå';
@override String endsAt({required Object time}) => 'Slutter kl. ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsNb {
'videoControls.exitFullscreenButton' => 'Avslutt fullskjerm',
'videoControls.alwaysOnTopButton' => 'Alltid øverst',
'videoControls.rotationLockButton' => 'Rotasjonslås',
'videoControls.lockScreen' => 'Lås skjerm',
'videoControls.unlockScreen' => 'Lås opp skjerm',
'videoControls.screenLockButton' => 'Skjermlås',
'videoControls.longPressToUnlock' => 'Langt trykk for å låse opp',
'videoControls.timelineSlider' => 'Videotidslinje',
'videoControls.volumeSlider' => 'Volumnivå',
'videoControls.endsAt' => ({required Object time}) => 'Slutter kl. ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsNb {
'liveTv.lateNight' => 'Sen kveld',
'liveTv.whatsOn' => 'Hva går nå',
'liveTv.watchChannel' => 'Se kanal',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoritter',
'collections.title' => 'Samlinger',
'collections.collection' => 'Samling',
'collections.empty' => 'Samlingen er tom',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Kan ikke slette: Ukjent bibliotekseksjon',
'collections.deleteCollection' => 'Slett samling',
'collections.deleteConfirm' => ({required Object title}) => 'Er du sikker på at du vil slette "${title}"? Denne handlingen kan ikke angres.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsNl implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Volledig scherm verlaten';
@override String get alwaysOnTopButton => 'Altijd bovenop';
@override String get rotationLockButton => 'Rotatievergrendeling';
@override String get lockScreen => 'Vergrendel scherm';
@override String get unlockScreen => 'Ontgrendel scherm';
@override String get screenLockButton => 'Schermvergrendeling';
@override String get longPressToUnlock => 'Lang indrukken om te ontgrendelen';
@override String get timelineSlider => 'Videotijdlijn';
@override String get volumeSlider => 'Volumeniveau';
@override String endsAt({required Object time}) => 'Eindigt om ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsNl {
'videoControls.exitFullscreenButton' => 'Volledig scherm verlaten',
'videoControls.alwaysOnTopButton' => 'Altijd bovenop',
'videoControls.rotationLockButton' => 'Rotatievergrendeling',
'videoControls.lockScreen' => 'Vergrendel scherm',
'videoControls.unlockScreen' => 'Ontgrendel scherm',
'videoControls.screenLockButton' => 'Schermvergrendeling',
'videoControls.longPressToUnlock' => 'Lang indrukken om te ontgrendelen',
'videoControls.timelineSlider' => 'Videotijdlijn',
'videoControls.volumeSlider' => 'Volumeniveau',
'videoControls.endsAt' => ({required Object time}) => 'Eindigt om ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsNl {
'liveTv.lateNight' => 'Late avond',
'liveTv.whatsOn' => 'Nu op TV',
'liveTv.watchChannel' => 'Kanaal bekijken',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favorieten',
'downloads.title' => 'Downloads',
'downloads.manage' => 'Beheren',
'downloads.tvShows' => 'Series',
_ => null,
} ?? switch (path) {
'downloads.movies' => 'Films',
'downloads.noDownloads' => 'Nog geen downloads',
'downloads.noDownloadsDescription' => 'Gedownloade content verschijnt hier voor offline weergave',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsPl implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Wyjdź z pełnego ekranu';
@override String get alwaysOnTopButton => 'Zawsze na wierzchu';
@override String get rotationLockButton => 'Blokada obrotu';
@override String get lockScreen => 'Zablokuj ekran';
@override String get unlockScreen => 'Odblokuj ekran';
@override String get screenLockButton => 'Blokada ekranu';
@override String get longPressToUnlock => 'Przytrzymaj, aby odblokować';
@override String get timelineSlider => 'Oś czasu wideo';
@override String get volumeSlider => 'Poziom głośności';
@override String endsAt({required Object time}) => 'Kończy się o ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsPl {
'videoControls.exitFullscreenButton' => 'Wyjdź z pełnego ekranu',
'videoControls.alwaysOnTopButton' => 'Zawsze na wierzchu',
'videoControls.rotationLockButton' => 'Blokada obrotu',
'videoControls.lockScreen' => 'Zablokuj ekran',
'videoControls.unlockScreen' => 'Odblokuj ekran',
'videoControls.screenLockButton' => 'Blokada ekranu',
'videoControls.longPressToUnlock' => 'Przytrzymaj, aby odblokować',
'videoControls.timelineSlider' => 'Oś czasu wideo',
'videoControls.volumeSlider' => 'Poziom głośności',
'videoControls.endsAt' => ({required Object time}) => 'Kończy się o ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsPl {
'liveTv.lateNight' => 'Późna noc',
'liveTv.whatsOn' => 'Co leci',
'liveTv.watchChannel' => 'Oglądaj kanał',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Ulubione',
'collections.title' => 'Kolekcje',
'collections.collection' => 'Kolekcja',
'collections.empty' => 'Kolekcja jest pusta',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Nie można usunąć: Nieznana sekcja biblioteki',
'collections.deleteCollection' => 'Usuń kolekcję',
'collections.deleteConfirm' => ({required Object title}) => 'Czy na pewno chcesz usunąć "${title}"? Tej operacji nie można cofnąć.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsPt implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Sair da tela cheia';
@override String get alwaysOnTopButton => 'Sempre no topo';
@override String get rotationLockButton => 'Travar rotação';
@override String get lockScreen => 'Travar tela';
@override String get unlockScreen => 'Destravar tela';
@override String get screenLockButton => 'Travar tela';
@override String get longPressToUnlock => 'Pressione e segure para destravar';
@override String get timelineSlider => 'Linha do tempo do vídeo';
@override String get volumeSlider => 'Nível de volume';
@override String endsAt({required Object time}) => 'Termina às ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsPt {
'videoControls.exitFullscreenButton' => 'Sair da tela cheia',
'videoControls.alwaysOnTopButton' => 'Sempre no topo',
'videoControls.rotationLockButton' => 'Travar rotação',
'videoControls.lockScreen' => 'Travar tela',
'videoControls.unlockScreen' => 'Destravar tela',
'videoControls.screenLockButton' => 'Travar tela',
'videoControls.longPressToUnlock' => 'Pressione e segure para destravar',
'videoControls.timelineSlider' => 'Linha do tempo do vídeo',
'videoControls.volumeSlider' => 'Nível de volume',
'videoControls.endsAt' => ({required Object time}) => 'Termina às ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsPt {
'liveTv.lateNight' => 'Madrugada',
'liveTv.whatsOn' => 'O que Está Passando',
'liveTv.watchChannel' => 'Assistir Canal',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoritos',
'collections.title' => 'Coleções',
'collections.collection' => 'Coleção',
'collections.empty' => 'A coleção está vazia',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Não é possível excluir: Seção de biblioteca desconhecida',
'collections.deleteCollection' => 'Excluir Coleção',
'collections.deleteConfirm' => ({required Object title}) => 'Tem certeza que deseja excluir "${title}"? Esta ação não pode ser desfeita.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsRu implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Выйти из полноэкранного режима';
@override String get alwaysOnTopButton => 'Всегда поверх';
@override String get rotationLockButton => 'Блокировка поворота';
@override String get lockScreen => 'Заблокировать экран';
@override String get unlockScreen => 'Разблокировать экран';
@override String get screenLockButton => 'Блокировка экрана';
@override String get longPressToUnlock => 'Удерживайте для разблокировки';
@override String get timelineSlider => 'Временная шкала';
@override String get volumeSlider => 'Уровень громкости';
@override String endsAt({required Object time}) => 'Закончится в ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsRu {
'videoControls.exitFullscreenButton' => 'Выйти из полноэкранного режима',
'videoControls.alwaysOnTopButton' => 'Всегда поверх',
'videoControls.rotationLockButton' => 'Блокировка поворота',
'videoControls.lockScreen' => 'Заблокировать экран',
'videoControls.unlockScreen' => 'Разблокировать экран',
'videoControls.screenLockButton' => 'Блокировка экрана',
'videoControls.longPressToUnlock' => 'Удерживайте для разблокировки',
'videoControls.timelineSlider' => 'Временная шкала',
'videoControls.volumeSlider' => 'Уровень громкости',
'videoControls.endsAt' => ({required Object time}) => 'Закончится в ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsRu {
'liveTv.lateNight' => 'Поздний вечер',
'liveTv.whatsOn' => 'Что идёт',
'liveTv.watchChannel' => 'Смотреть канал',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Избранное',
'collections.title' => 'Коллекции',
'collections.collection' => 'Коллекция',
'collections.empty' => 'Коллекция пуста',
_ => null,
} ?? switch (path) {
'collections.unknownLibrarySection' => 'Невозможно удалить: неизвестный раздел библиотеки',
'collections.deleteCollection' => 'Удалить коллекцию',
'collections.deleteConfirm' => ({required Object title}) => 'Вы уверены, что хотите удалить "${title}"? Это действие нельзя отменить.',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsSv implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => 'Avsluta helskärm';
@override String get alwaysOnTopButton => 'Alltid överst';
@override String get rotationLockButton => 'Rotationslås';
@override String get lockScreen => 'Lås skärm';
@override String get unlockScreen => 'Lås upp skärm';
@override String get screenLockButton => 'Skärmlås';
@override String get longPressToUnlock => 'Tryck länge för att låsa upp';
@override String get timelineSlider => 'Videotidslinje';
@override String get volumeSlider => 'Volymnivå';
@override String endsAt({required Object time}) => 'Slutar ${time}';
@@ -1601,6 +1605,10 @@ extension on TranslationsSv {
'videoControls.exitFullscreenButton' => 'Avsluta helskärm',
'videoControls.alwaysOnTopButton' => 'Alltid överst',
'videoControls.rotationLockButton' => 'Rotationslås',
'videoControls.lockScreen' => 'Lås skärm',
'videoControls.unlockScreen' => 'Lås upp skärm',
'videoControls.screenLockButton' => 'Skärmlås',
'videoControls.longPressToUnlock' => 'Tryck länge för att låsa upp',
'videoControls.timelineSlider' => 'Videotidslinje',
'videoControls.volumeSlider' => 'Volymnivå',
'videoControls.endsAt' => ({required Object time}) => 'Slutar ${time}',
@@ -1789,12 +1797,12 @@ extension on TranslationsSv {
'liveTv.lateNight' => 'Sen kväll',
'liveTv.whatsOn' => 'På TV nu',
'liveTv.watchChannel' => 'Titta på kanal',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => 'Favoriter',
'downloads.title' => 'Nedladdningar',
'downloads.manage' => 'Hantera',
'downloads.tvShows' => 'TV-serier',
_ => null,
} ?? switch (path) {
'downloads.movies' => 'Filmer',
'downloads.noDownloads' => 'Inga nedladdningar ännu',
'downloads.noDownloadsDescription' => 'Nedladdat innehåll visas här för offline-visning',
+10 -2
View File
@@ -493,6 +493,10 @@ class _TranslationsVideoControlsZh implements TranslationsVideoControlsEn {
@override String get exitFullscreenButton => '退出全屏';
@override String get alwaysOnTopButton => '置顶窗口';
@override String get rotationLockButton => '旋转锁定';
@override String get lockScreen => '锁定屏幕';
@override String get unlockScreen => '解锁屏幕';
@override String get screenLockButton => '屏幕锁定';
@override String get longPressToUnlock => '长按解锁';
@override String get timelineSlider => '视频时间轴';
@override String get volumeSlider => '音量调节';
@override String endsAt({required Object time}) => '${time} 结束';
@@ -1601,6 +1605,10 @@ extension on TranslationsZh {
'videoControls.exitFullscreenButton' => '退出全屏',
'videoControls.alwaysOnTopButton' => '置顶窗口',
'videoControls.rotationLockButton' => '旋转锁定',
'videoControls.lockScreen' => '锁定屏幕',
'videoControls.unlockScreen' => '解锁屏幕',
'videoControls.screenLockButton' => '屏幕锁定',
'videoControls.longPressToUnlock' => '长按解锁',
'videoControls.timelineSlider' => '视频时间轴',
'videoControls.volumeSlider' => '音量调节',
'videoControls.endsAt' => ({required Object time}) => '${time} 结束',
@@ -1789,12 +1797,12 @@ extension on TranslationsZh {
'liveTv.lateNight' => '深夜',
'liveTv.whatsOn' => '正在播出',
'liveTv.watchChannel' => '观看频道',
_ => null,
} ?? switch (path) {
'liveTv.favorites' => '收藏',
'downloads.title' => '下载',
'downloads.manage' => '管理',
'downloads.tvShows' => '电视剧',
_ => null,
} ?? switch (path) {
'downloads.movies' => '电影',
'downloads.noDownloads' => '暂无下载',
'downloads.noDownloadsDescription' => '下载的内容将在此处显示以供离线观看',
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "Avsluta helskärm",
"alwaysOnTopButton": "Alltid överst",
"rotationLockButton": "Rotationslås",
"lockScreen": "Lås skärm",
"unlockScreen": "Lås upp skärm",
"screenLockButton": "Skärmlås",
"longPressToUnlock": "Tryck länge för att låsa upp",
"timelineSlider": "Videotidslinje",
"volumeSlider": "Volymnivå",
"endsAt": "Slutar ${time}",
+4
View File
@@ -346,6 +346,10 @@
"exitFullscreenButton": "退出全屏",
"alwaysOnTopButton": "置顶窗口",
"rotationLockButton": "旋转锁定",
"lockScreen": "锁定屏幕",
"unlockScreen": "解锁屏幕",
"screenLockButton": "屏幕锁定",
"longPressToUnlock": "长按解锁",
"timelineSlider": "视频时间轴",
"volumeSlider": "音量调节",
"endsAt": "${time} 结束",
@@ -13,11 +13,13 @@ class TrackControlsState {
final int audioSyncOffset;
final int subtitleSyncOffset;
final bool isRotationLocked;
final bool isScreenLocked;
final bool isFullscreen;
final bool isAlwaysOnTop;
final VoidCallback? onTogglePIPMode;
final VoidCallback? onCycleBoxFitMode;
final VoidCallback? onToggleRotationLock;
final VoidCallback? onToggleScreenLock;
final VoidCallback? onToggleFullscreen;
final VoidCallback? onToggleAlwaysOnTop;
final Function(int)? onSwitchVersion;
@@ -46,11 +48,13 @@ class TrackControlsState {
this.audioSyncOffset = 0,
this.subtitleSyncOffset = 0,
this.isRotationLocked = false,
this.isScreenLocked = false,
this.isFullscreen = false,
this.isAlwaysOnTop = false,
this.onTogglePIPMode,
this.onCycleBoxFitMode,
this.onToggleRotationLock,
this.onToggleScreenLock,
this.onToggleFullscreen,
this.onToggleAlwaysOnTop,
this.onSwitchVersion,
@@ -225,6 +225,9 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
int _audioSyncOffset = 0; // Default, loaded from settings
int _subtitleSyncOffset = 0; // Default, loaded from settings
bool _isRotationLocked = true; // Default locked (landscape only)
bool _isScreenLocked = false; // Touch lock during playback
bool _showLockIcon = false; // Whether to show the lock overlay icon
Timer? _lockIconTimer;
bool _clickVideoTogglesPlayback = false; // Default, loaded from settings
bool _isContentStripVisible = false; // Whether the swipe-up content strip is showing
@@ -663,6 +666,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
widget.hasFirstFrame?.removeListener(_onFirstFrameReady);
_hideTimer?.cancel();
_feedbackTimer?.cancel();
_lockIconTimer?.cancel();
_autoSkipTimer?.cancel();
_skipButtonDismissTimer?.cancel();
_singleTapTimer?.cancel();
@@ -900,6 +904,38 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
}
}
void _toggleScreenLock() {
final locking = !_isScreenLocked;
setState(() {
_isScreenLocked = locking;
if (locking) {
_showLockIcon = true;
}
});
if (locking) {
_hideControls();
_startLockIconHideTimer();
}
}
void _startLockIconHideTimer() {
_lockIconTimer?.cancel();
_lockIconTimer = Timer(const Duration(seconds: 3), () {
if (mounted) setState(() => _showLockIcon = false);
});
}
void _unlockScreen() {
setState(() {
_isScreenLocked = false;
_showLockIcon = false;
_showControls = true;
});
_lockIconTimer?.cancel();
widget.controlsVisible?.value = true;
_startHideTimer();
}
void _updateTrafficLightVisibility() async {
// When maximized or fullscreen, always keep traffic lights visible so the
// user can reach them without the controls-hide-on-mouse-leave race.
@@ -1050,6 +1086,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
audioSyncOffset: _audioSyncOffset,
subtitleSyncOffset: _subtitleSyncOffset,
isRotationLocked: _isRotationLocked,
isScreenLocked: _isScreenLocked,
isFullscreen: _isFullscreen,
isAlwaysOnTop: _isAlwaysOnTop,
onTogglePIPMode: (_isPipSupported && !PlatformDetector.isTV())
@@ -1057,6 +1094,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
: null,
onCycleBoxFitMode: widget.player.playerType != 'exoplayer' ? widget.onCycleBoxFitMode : null,
onToggleRotationLock: _toggleRotationLock,
onToggleScreenLock: _toggleScreenLock,
onToggleFullscreen: _toggleFullscreen,
onToggleAlwaysOnTop: onToggleAlwaysOnTop,
onSwitchVersion: _switchMediaVersion,
@@ -2110,6 +2148,42 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
left: 16,
child: IgnorePointer(child: PlayerPerformanceOverlay(player: widget.player)),
),
// Screen lock overlay - absorbs all touches when active
if (_isScreenLocked)
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() => _showLockIcon = true);
_startLockIconHideTimer();
},
onLongPress: _unlockScreen,
child: AnimatedOpacity(
opacity: _showLockIcon ? 1.0 : 0.0,
duration: const Duration(milliseconds: 200),
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.6),
borderRadius: const BorderRadius.all(Radius.circular(28)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const AppIcon(Symbols.lock_rounded, fill: 1, color: Colors.white, size: 20),
const SizedBox(width: 8),
Text(
t.videoControls.longPressToUnlock,
style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
),
),
),
),
),
],
),
),
@@ -70,11 +70,13 @@ class TrackChapterControls extends StatelessWidget {
int get audioSyncOffset => trackControlsState.audioSyncOffset;
int get subtitleSyncOffset => trackControlsState.subtitleSyncOffset;
bool get isRotationLocked => trackControlsState.isRotationLocked;
bool get isScreenLocked => trackControlsState.isScreenLocked;
bool get isFullscreen => trackControlsState.isFullscreen;
bool get isAlwaysOnTop => trackControlsState.isAlwaysOnTop;
VoidCallback? get onTogglePIPMode => trackControlsState.onTogglePIPMode;
VoidCallback? get onCycleBoxFitMode => trackControlsState.onCycleBoxFitMode;
VoidCallback? get onToggleRotationLock => trackControlsState.onToggleRotationLock;
VoidCallback? get onToggleScreenLock => trackControlsState.onToggleScreenLock;
VoidCallback? get onToggleFullscreen => trackControlsState.onToggleFullscreen;
VoidCallback? get onToggleAlwaysOnTop => trackControlsState.onToggleAlwaysOnTop;
Function(int)? get onSwitchVersion => trackControlsState.onSwitchVersion;
@@ -404,6 +406,24 @@ class TrackChapterControls extends StatelessWidget {
buttonIndex++;
}
// Screen lock button (mobile only, not on TV)
if (isMobile && !PlatformDetector.isTV()) {
final currentIndex = buttonIndex;
buttons.add(
_buildTrackButton(
buttonIndex: currentIndex,
icon: Symbols.lock_rounded,
tooltip: t.videoControls.lockScreen,
semanticLabel: t.videoControls.screenLockButton,
tracks: tracks,
isMobile: isMobile,
isDesktop: isDesktop,
onPressed: onToggleScreenLock,
),
);
buttonIndex++;
}
// Always on top button (desktop only, not TV)
if (isDesktop && onToggleAlwaysOnTop != null) {
final currentIndex = buttonIndex;