feat: watch together recent rooms, plex usernames, action toasts, shorter codes
close #855
This commit is contained in:
@@ -702,10 +702,10 @@
|
||||
"leave": "Forlad",
|
||||
"syncing": "Synkroniserer...",
|
||||
"joinWatchSession": "Deltag i se-session",
|
||||
"enterCodeHint": "Indtast 8-tegns kode",
|
||||
"enterCodeHint": "Indtast 5-tegns kode",
|
||||
"pasteFromClipboard": "Indsæt fra udklipsholder",
|
||||
"pleaseEnterCode": "Indtast en sessionskode",
|
||||
"codeMustBe8Chars": "Sessionskode skal være 8 tegn",
|
||||
"codeMustBe5Chars": "Sessionskode skal være 5 tegn",
|
||||
"joinInstructions": "Indtast sessionskoden delt af værten for at deltage i se-sessionen.",
|
||||
"failedToCreate": "Kunne ikke oprette session",
|
||||
"failedToJoin": "Kunne ikke deltage i session",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Hop tilbage til det værten ser nu",
|
||||
"failedToOpenCurrentPlayback": "Kunne ikke åbne nuværende afspilning",
|
||||
"participantJoined": "${name} deltog",
|
||||
"participantLeft": "${name} forlod"
|
||||
"participantLeft": "${name} forlod",
|
||||
"participantPaused": "${name} satte på pause",
|
||||
"participantResumed": "${name} genoptog",
|
||||
"participantSeeked": "${name} spoled",
|
||||
"recentRooms": "Seneste rum",
|
||||
"renameRoom": "Omdøb rum",
|
||||
"removeRoom": "Fjern"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Downloads",
|
||||
|
||||
@@ -729,10 +729,10 @@
|
||||
"leave": "Verlassen",
|
||||
"syncing": "Synchronisieren...",
|
||||
"joinWatchSession": "Schausitzung Beitreten",
|
||||
"enterCodeHint": "8-stelligen Code eingeben",
|
||||
"enterCodeHint": "5-stelligen Code eingeben",
|
||||
"pasteFromClipboard": "Aus Zwischenablage einfügen",
|
||||
"pleaseEnterCode": "Bitte gib einen Sitzungscode ein",
|
||||
"codeMustBe8Chars": "Sitzungscode muss 8 Zeichen haben",
|
||||
"codeMustBe5Chars": "Sitzungscode muss 5 Zeichen haben",
|
||||
"joinInstructions": "Gib den vom Host geteilten Sitzungscode ein, um seiner Schausitzung beizutreten.",
|
||||
"failedToCreate": "Sitzung konnte nicht erstellt werden",
|
||||
"failedToJoin": "Sitzung konnte nicht beigetreten werden",
|
||||
@@ -744,7 +744,13 @@
|
||||
"joinCurrentPlaybackDescription": "Springe zurück zu dem, was der Host gerade ansieht",
|
||||
"failedToOpenCurrentPlayback": "Aktuelle Wiedergabe konnte nicht geöffnet werden",
|
||||
"participantJoined": "${name} ist beigetreten",
|
||||
"participantLeft": "${name} hat die Sitzung verlassen"
|
||||
"participantLeft": "${name} hat die Sitzung verlassen",
|
||||
"participantPaused": "${name} hat pausiert",
|
||||
"participantResumed": "${name} hat fortgesetzt",
|
||||
"participantSeeked": "${name} hat gespult",
|
||||
"recentRooms": "Letzte Räume",
|
||||
"renameRoom": "Raum umbenennen",
|
||||
"removeRoom": "Entfernen"
|
||||
},
|
||||
"shaders": {
|
||||
"title": "Shader",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Leave",
|
||||
"syncing": "Syncing...",
|
||||
"joinWatchSession": "Join Watch Session",
|
||||
"enterCodeHint": "Enter 8-character code",
|
||||
"enterCodeHint": "Enter 5-character code",
|
||||
"pasteFromClipboard": "Paste from clipboard",
|
||||
"pleaseEnterCode": "Please enter a session code",
|
||||
"codeMustBe8Chars": "Session code must be 8 characters",
|
||||
"codeMustBe5Chars": "Session code must be 5 characters",
|
||||
"joinInstructions": "Enter the session code shared by the host to join their watch session.",
|
||||
"failedToCreate": "Failed to create session",
|
||||
"failedToJoin": "Failed to join session",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Jump back into what the host is currently watching",
|
||||
"failedToOpenCurrentPlayback": "Failed to open current playback",
|
||||
"participantJoined": "${name} joined",
|
||||
"participantLeft": "${name} left"
|
||||
"participantLeft": "${name} left",
|
||||
"participantPaused": "${name} paused",
|
||||
"participantResumed": "${name} resumed",
|
||||
"participantSeeked": "${name} seeked",
|
||||
"recentRooms": "Recent Rooms",
|
||||
"renameRoom": "Rename Room",
|
||||
"removeRoom": "Remove"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Downloads",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Salir",
|
||||
"syncing": "Sincronizando...",
|
||||
"joinWatchSession": "Unirse a Sesión de Visualización",
|
||||
"enterCodeHint": "Introduce el código de 8 caracteres",
|
||||
"enterCodeHint": "Introduce el código de 5 caracteres",
|
||||
"pasteFromClipboard": "Pegar desde el portapapeles",
|
||||
"pleaseEnterCode": "Por favor, introduce un código de sesión",
|
||||
"codeMustBe8Chars": "El código de sesión debe tener 8 caracteres",
|
||||
"codeMustBe5Chars": "El código de sesión debe tener 5 caracteres",
|
||||
"joinInstructions": "Introduce el código de sesión compartido por el anfitrión para unirte a su sesión.",
|
||||
"failedToCreate": "Error al crear la sesión",
|
||||
"failedToJoin": "Error al unirse a la sesión",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Vuelve a lo que el anfitrión está viendo ahora mismo",
|
||||
"failedToOpenCurrentPlayback": "No se pudo abrir la reproducción actual",
|
||||
"participantJoined": "${name} se unió",
|
||||
"participantLeft": "${name} se fue"
|
||||
"participantLeft": "${name} se fue",
|
||||
"participantPaused": "${name} pausó",
|
||||
"participantResumed": "${name} reanudó",
|
||||
"participantSeeked": "${name} avanzó",
|
||||
"recentRooms": "Salas recientes",
|
||||
"renameRoom": "Renombrar sala",
|
||||
"removeRoom": "Eliminar"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Descargas",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Fin",
|
||||
"syncing": "Synchronisation...",
|
||||
"joinWatchSession": "Rejoindre la session de visionnage",
|
||||
"enterCodeHint": "Entrez le code à 8 caractères",
|
||||
"enterCodeHint": "Entrez le code à 5 caractères",
|
||||
"pasteFromClipboard": "Coller depuis le presse-papiers",
|
||||
"pleaseEnterCode": "Veuillez saisir un code de session",
|
||||
"codeMustBe8Chars": "Le code de session doit comporter 8 caractères",
|
||||
"codeMustBe5Chars": "Le code de session doit comporter 5 caractères",
|
||||
"joinInstructions": "Entrez le code de session partagé par l'hôte pour rejoindre sa session de visionnage.",
|
||||
"failedToCreate": "Échec de la création de la session",
|
||||
"failedToJoin": "Échec de la connexion à la session",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Revenez à ce que l'hôte regarde actuellement",
|
||||
"failedToOpenCurrentPlayback": "Impossible d'ouvrir la lecture en cours",
|
||||
"participantJoined": "${name} a rejoint",
|
||||
"participantLeft": "${name} est parti"
|
||||
"participantLeft": "${name} est parti",
|
||||
"participantPaused": "${name} a mis en pause",
|
||||
"participantResumed": "${name} a repris",
|
||||
"participantSeeked": "${name} a avancé",
|
||||
"recentRooms": "Salons récents",
|
||||
"renameRoom": "Renommer le salon",
|
||||
"removeRoom": "Supprimer"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Téléchargements",
|
||||
|
||||
@@ -729,10 +729,10 @@
|
||||
"leave": "Lascia",
|
||||
"syncing": "Sincronizzazione...",
|
||||
"joinWatchSession": "Unisciti alla Sessione di Visione",
|
||||
"enterCodeHint": "Inserisci codice di 8 caratteri",
|
||||
"enterCodeHint": "Inserisci codice di 5 caratteri",
|
||||
"pasteFromClipboard": "Incolla dagli appunti",
|
||||
"pleaseEnterCode": "Inserisci un codice sessione",
|
||||
"codeMustBe8Chars": "Il codice sessione deve essere di 8 caratteri",
|
||||
"codeMustBe5Chars": "Il codice sessione deve essere di 5 caratteri",
|
||||
"joinInstructions": "Inserisci il codice sessione condiviso dall'host per unirti alla loro sessione di visione.",
|
||||
"failedToCreate": "Impossibile creare la sessione",
|
||||
"failedToJoin": "Impossibile unirsi alla sessione",
|
||||
@@ -744,7 +744,13 @@
|
||||
"joinCurrentPlaybackDescription": "Torna a ciò che l'host sta guardando in questo momento",
|
||||
"failedToOpenCurrentPlayback": "Impossibile aprire la riproduzione corrente",
|
||||
"participantJoined": "${name} si è unito",
|
||||
"participantLeft": "${name} se ne è andato"
|
||||
"participantLeft": "${name} se ne è andato",
|
||||
"participantPaused": "${name} ha messo in pausa",
|
||||
"participantResumed": "${name} ha ripreso",
|
||||
"participantSeeked": "${name} ha cercato",
|
||||
"recentRooms": "Stanze recenti",
|
||||
"renameRoom": "Rinomina stanza",
|
||||
"removeRoom": "Rimuovi"
|
||||
},
|
||||
"shaders": {
|
||||
"title": "Shader",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "退出",
|
||||
"syncing": "同期中...",
|
||||
"joinWatchSession": "視聴セッションに参加",
|
||||
"enterCodeHint": "8文字のコードを入力",
|
||||
"enterCodeHint": "5文字のコードを入力",
|
||||
"pasteFromClipboard": "クリップボードから貼り付け",
|
||||
"pleaseEnterCode": "セッションコードを入力してください",
|
||||
"codeMustBe8Chars": "セッションコードは8文字である必要があります",
|
||||
"codeMustBe5Chars": "セッションコードは5文字である必要があります",
|
||||
"joinInstructions": "ホストが共有したセッションコードを入力して視聴セッションに参加してください。",
|
||||
"failedToCreate": "セッションの作成に失敗しました",
|
||||
"failedToJoin": "セッションへの参加に失敗しました",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "ホストが現在視聴中のコンテンツに戻る",
|
||||
"failedToOpenCurrentPlayback": "現在の再生を開けませんでした",
|
||||
"participantJoined": "${name}が参加しました",
|
||||
"participantLeft": "${name}が退出しました"
|
||||
"participantLeft": "${name}が退出しました",
|
||||
"participantPaused": "${name}が一時停止しました",
|
||||
"participantResumed": "${name}が再開しました",
|
||||
"participantSeeked": "${name}がシークしました",
|
||||
"recentRooms": "最近のルーム",
|
||||
"renameRoom": "ルーム名を変更",
|
||||
"removeRoom": "削除"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "ダウンロード",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "이탈",
|
||||
"syncing": "동기화 중...",
|
||||
"joinWatchSession": "시청 세션에 참여",
|
||||
"enterCodeHint": "8자리 코드 입력",
|
||||
"enterCodeHint": "5자리 코드 입력",
|
||||
"pasteFromClipboard": "클립보드에서 붙여넣기",
|
||||
"pleaseEnterCode": "세션 코드를 입력하세요",
|
||||
"codeMustBe8Chars": "세션 코드는 반드시 8자리여야 합니다",
|
||||
"codeMustBe5Chars": "세션 코드는 반드시 5자리여야 합니다",
|
||||
"joinInstructions": "호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.",
|
||||
"failedToCreate": "세션 생성 실패",
|
||||
"failedToJoin": "세션 참여 실패",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "호스트가 현재 보고 있는 항목으로 돌아갑니다",
|
||||
"failedToOpenCurrentPlayback": "현재 재생을 열 수 없습니다",
|
||||
"participantJoined": "${name}님이 참여했습니다",
|
||||
"participantLeft": "${name}님이 나갔습니다"
|
||||
"participantLeft": "${name}님이 나갔습니다",
|
||||
"participantPaused": "${name}님이 일시정지했습니다",
|
||||
"participantResumed": "${name}님이 재생했습니다",
|
||||
"participantSeeked": "${name}님이 탐색했습니다",
|
||||
"recentRooms": "최근 방",
|
||||
"renameRoom": "방 이름 변경",
|
||||
"removeRoom": "제거"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "다운로드",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Forlat",
|
||||
"syncing": "Synkroniserer...",
|
||||
"joinWatchSession": "Bli med i se sammen-økt",
|
||||
"enterCodeHint": "Skriv inn 8-tegns kode",
|
||||
"enterCodeHint": "Skriv inn 5-tegns kode",
|
||||
"pasteFromClipboard": "Lim inn fra utklippstavle",
|
||||
"pleaseEnterCode": "Vennligst skriv inn en øktkode",
|
||||
"codeMustBe8Chars": "Øktkoden må være 8 tegn",
|
||||
"codeMustBe5Chars": "Øktkoden må være 5 tegn",
|
||||
"joinInstructions": "Skriv inn øktkoden delt av verten for å bli med i se sammen-økten.",
|
||||
"failedToCreate": "Kunne ikke opprette økt",
|
||||
"failedToJoin": "Kunne ikke bli med i økt",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Hopp tilbake til det verten ser på nå",
|
||||
"failedToOpenCurrentPlayback": "Kunne ikke åpne gjeldende avspilling",
|
||||
"participantJoined": "${name} ble med",
|
||||
"participantLeft": "${name} forlot"
|
||||
"participantLeft": "${name} forlot",
|
||||
"participantPaused": "${name} pauset",
|
||||
"participantResumed": "${name} gjenopptok",
|
||||
"participantSeeked": "${name} spolet",
|
||||
"recentRooms": "Nylige rom",
|
||||
"renameRoom": "Gi nytt navn til rom",
|
||||
"removeRoom": "Fjern"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Nedlastinger",
|
||||
|
||||
@@ -729,10 +729,10 @@
|
||||
"leave": "Verlaten",
|
||||
"syncing": "Synchroniseren...",
|
||||
"joinWatchSession": "Kijksessie Deelnemen",
|
||||
"enterCodeHint": "Voer 8-teken code in",
|
||||
"enterCodeHint": "Voer 5-teken code in",
|
||||
"pasteFromClipboard": "Plakken van klembord",
|
||||
"pleaseEnterCode": "Voer een sessiecode in",
|
||||
"codeMustBe8Chars": "Sessiecode moet 8 tekens zijn",
|
||||
"codeMustBe5Chars": "Sessiecode moet 5 tekens zijn",
|
||||
"joinInstructions": "Voer de sessiecode in die door de host is gedeeld om deel te nemen aan hun kijksessie.",
|
||||
"failedToCreate": "Sessie maken mislukt",
|
||||
"failedToJoin": "Sessie deelnemen mislukt",
|
||||
@@ -744,7 +744,13 @@
|
||||
"joinCurrentPlaybackDescription": "Ga terug naar wat de host nu kijkt",
|
||||
"failedToOpenCurrentPlayback": "Huidige weergave kon niet worden geopend",
|
||||
"participantJoined": "${name} is toegetreden",
|
||||
"participantLeft": "${name} heeft de sessie verlaten"
|
||||
"participantLeft": "${name} heeft de sessie verlaten",
|
||||
"participantPaused": "${name} heeft gepauzeerd",
|
||||
"participantResumed": "${name} heeft hervat",
|
||||
"participantSeeked": "${name} heeft gespoeld",
|
||||
"recentRooms": "Recente kamers",
|
||||
"renameRoom": "Kamer hernoemen",
|
||||
"removeRoom": "Verwijderen"
|
||||
},
|
||||
"shaders": {
|
||||
"title": "Shaders",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Opuść",
|
||||
"syncing": "Synchronizacja...",
|
||||
"joinWatchSession": "Dołącz do sesji oglądania",
|
||||
"enterCodeHint": "Wprowadź 8-znakowy kod",
|
||||
"enterCodeHint": "Wprowadź 5-znakowy kod",
|
||||
"pasteFromClipboard": "Wklej ze schowka",
|
||||
"pleaseEnterCode": "Wprowadź kod sesji",
|
||||
"codeMustBe8Chars": "Kod sesji musi mieć 8 znaków",
|
||||
"codeMustBe5Chars": "Kod sesji musi mieć 5 znaków",
|
||||
"joinInstructions": "Wprowadź kod sesji udostępniony przez hosta, aby dołączyć do sesji oglądania.",
|
||||
"failedToCreate": "Nie udało się utworzyć sesji",
|
||||
"failedToJoin": "Nie udało się dołączyć do sesji",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Wróć do tego, co host aktualnie ogląda",
|
||||
"failedToOpenCurrentPlayback": "Nie udało się otworzyć bieżącego odtwarzania",
|
||||
"participantJoined": "${name} dołączył",
|
||||
"participantLeft": "${name} opuścił"
|
||||
"participantLeft": "${name} opuścił",
|
||||
"participantPaused": "${name} wstrzymał",
|
||||
"participantResumed": "${name} wznowił",
|
||||
"participantSeeked": "${name} przewinął",
|
||||
"recentRooms": "Ostatnie pokoje",
|
||||
"renameRoom": "Zmień nazwę pokoju",
|
||||
"removeRoom": "Usuń"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Pobrania",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Sair",
|
||||
"syncing": "Sincronizando...",
|
||||
"joinWatchSession": "Entrar na Sessão",
|
||||
"enterCodeHint": "Insira o código de 8 caracteres",
|
||||
"enterCodeHint": "Insira o código de 5 caracteres",
|
||||
"pasteFromClipboard": "Colar da área de transferência",
|
||||
"pleaseEnterCode": "Insira um código de sessão",
|
||||
"codeMustBe8Chars": "O código da sessão deve ter 8 caracteres",
|
||||
"codeMustBe5Chars": "O código da sessão deve ter 5 caracteres",
|
||||
"joinInstructions": "Insira o código da sessão compartilhado pelo anfitrião para entrar na sessão.",
|
||||
"failedToCreate": "Falha ao criar sessão",
|
||||
"failedToJoin": "Falha ao entrar na sessão",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Voltar ao que o anfitrião está assistindo agora",
|
||||
"failedToOpenCurrentPlayback": "Falha ao abrir reprodução atual",
|
||||
"participantJoined": "${name} entrou",
|
||||
"participantLeft": "${name} saiu"
|
||||
"participantLeft": "${name} saiu",
|
||||
"participantPaused": "${name} pausou",
|
||||
"participantResumed": "${name} retomou",
|
||||
"participantSeeked": "${name} avançou",
|
||||
"recentRooms": "Salas recentes",
|
||||
"renameRoom": "Renomear sala",
|
||||
"removeRoom": "Remover"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Downloads",
|
||||
|
||||
@@ -702,10 +702,10 @@
|
||||
"leave": "Покинуть",
|
||||
"syncing": "Синхронизация...",
|
||||
"joinWatchSession": "Присоединиться к просмотру",
|
||||
"enterCodeHint": "Введите 8-символьный код",
|
||||
"enterCodeHint": "Введите 5-символьный код",
|
||||
"pasteFromClipboard": "Вставить из буфера обмена",
|
||||
"pleaseEnterCode": "Введите код сессии",
|
||||
"codeMustBe8Chars": "Код сессии должен содержать 8 символов",
|
||||
"codeMustBe5Chars": "Код сессии должен содержать 5 символов",
|
||||
"joinInstructions": "Введите код сессии, предоставленный хостом, чтобы присоединиться к просмотру.",
|
||||
"failedToCreate": "Не удалось создать сессию",
|
||||
"failedToJoin": "Не удалось присоединиться к сессии",
|
||||
@@ -717,7 +717,13 @@
|
||||
"joinCurrentPlaybackDescription": "Вернуться к тому, что сейчас смотрит хост",
|
||||
"failedToOpenCurrentPlayback": "Не удалось открыть текущее воспроизведение",
|
||||
"participantJoined": "${name} присоединился",
|
||||
"participantLeft": "${name} вышел"
|
||||
"participantLeft": "${name} вышел",
|
||||
"participantPaused": "${name} поставил на паузу",
|
||||
"participantResumed": "${name} возобновил",
|
||||
"participantSeeked": "${name} перемотал",
|
||||
"recentRooms": "Недавние комнаты",
|
||||
"renameRoom": "Переименовать комнату",
|
||||
"removeRoom": "Удалить"
|
||||
},
|
||||
"downloads": {
|
||||
"title": "Загрузки",
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 15
|
||||
/// Strings: 12975 (865 per locale)
|
||||
/// Strings: 13065 (871 per locale)
|
||||
///
|
||||
/// Built on 2026-04-11 at 05:59 UTC
|
||||
/// Built on 2026-04-13 at 10:11 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherDa implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Forlad';
|
||||
@override String get syncing => 'Synkroniserer...';
|
||||
@override String get joinWatchSession => 'Deltag i se-session';
|
||||
@override String get enterCodeHint => 'Indtast 8-tegns kode';
|
||||
@override String get enterCodeHint => 'Indtast 5-tegns kode';
|
||||
@override String get pasteFromClipboard => 'Indsæt fra udklipsholder';
|
||||
@override String get pleaseEnterCode => 'Indtast en sessionskode';
|
||||
@override String get codeMustBe8Chars => 'Sessionskode skal være 8 tegn';
|
||||
@override String get codeMustBe5Chars => 'Sessionskode skal være 5 tegn';
|
||||
@override String get joinInstructions => 'Indtast sessionskoden delt af værten for at deltage i se-sessionen.';
|
||||
@override String get failedToCreate => 'Kunne ikke oprette session';
|
||||
@override String get failedToJoin => 'Kunne ikke deltage i session';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherDa implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Kunne ikke åbne nuværende afspilning';
|
||||
@override String participantJoined({required Object name}) => '${name} deltog';
|
||||
@override String participantLeft({required Object name}) => '${name} forlod';
|
||||
@override String participantPaused({required Object name}) => '${name} satte på pause';
|
||||
@override String participantResumed({required Object name}) => '${name} genoptog';
|
||||
@override String participantSeeked({required Object name}) => '${name} spoled';
|
||||
@override String get recentRooms => 'Seneste rum';
|
||||
@override String get renameRoom => 'Omdøb rum';
|
||||
@override String get removeRoom => 'Fjern';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsDa {
|
||||
'watchTogether.leave' => 'Forlad',
|
||||
'watchTogether.syncing' => 'Synkroniserer...',
|
||||
'watchTogether.joinWatchSession' => 'Deltag i se-session',
|
||||
'watchTogether.enterCodeHint' => 'Indtast 8-tegns kode',
|
||||
'watchTogether.enterCodeHint' => 'Indtast 5-tegns kode',
|
||||
'watchTogether.pasteFromClipboard' => 'Indsæt fra udklipsholder',
|
||||
'watchTogether.pleaseEnterCode' => 'Indtast en sessionskode',
|
||||
'watchTogether.codeMustBe8Chars' => 'Sessionskode skal være 8 tegn',
|
||||
'watchTogether.codeMustBe5Chars' => 'Sessionskode skal være 5 tegn',
|
||||
'watchTogether.joinInstructions' => 'Indtast sessionskoden delt af værten for at deltage i se-sessionen.',
|
||||
'watchTogether.failedToCreate' => 'Kunne ikke oprette session',
|
||||
'watchTogether.failedToJoin' => 'Kunne ikke deltage i session',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsDa {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Kunne ikke åbne nuværende afspilning',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} deltog',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} forlod',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} satte på pause',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} genoptog',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} spoled',
|
||||
'watchTogether.recentRooms' => 'Seneste rum',
|
||||
'watchTogether.renameRoom' => 'Omdøb rum',
|
||||
'watchTogether.removeRoom' => 'Fjern',
|
||||
'downloads.title' => 'Downloads',
|
||||
'downloads.manage' => 'Administrer',
|
||||
'downloads.tvShows' => 'TV-serier',
|
||||
|
||||
@@ -989,10 +989,10 @@ class _TranslationsWatchTogetherDe implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Verlassen';
|
||||
@override String get syncing => 'Synchronisieren...';
|
||||
@override String get joinWatchSession => 'Schausitzung Beitreten';
|
||||
@override String get enterCodeHint => '8-stelligen Code eingeben';
|
||||
@override String get enterCodeHint => '5-stelligen Code eingeben';
|
||||
@override String get pasteFromClipboard => 'Aus Zwischenablage einfügen';
|
||||
@override String get pleaseEnterCode => 'Bitte gib einen Sitzungscode ein';
|
||||
@override String get codeMustBe8Chars => 'Sitzungscode muss 8 Zeichen haben';
|
||||
@override String get codeMustBe5Chars => 'Sitzungscode muss 5 Zeichen haben';
|
||||
@override String get joinInstructions => 'Gib den vom Host geteilten Sitzungscode ein, um seiner Schausitzung beizutreten.';
|
||||
@override String get failedToCreate => 'Sitzung konnte nicht erstellt werden';
|
||||
@override String get failedToJoin => 'Sitzung konnte nicht beigetreten werden';
|
||||
@@ -1005,6 +1005,12 @@ class _TranslationsWatchTogetherDe implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Aktuelle Wiedergabe konnte nicht geöffnet werden';
|
||||
@override String participantJoined({required Object name}) => '${name} ist beigetreten';
|
||||
@override String participantLeft({required Object name}) => '${name} hat die Sitzung verlassen';
|
||||
@override String participantPaused({required Object name}) => '${name} hat pausiert';
|
||||
@override String participantResumed({required Object name}) => '${name} hat fortgesetzt';
|
||||
@override String participantSeeked({required Object name}) => '${name} hat gespult';
|
||||
@override String get recentRooms => 'Letzte Räume';
|
||||
@override String get renameRoom => 'Raum umbenennen';
|
||||
@override String get removeRoom => 'Entfernen';
|
||||
}
|
||||
|
||||
// Path: shaders
|
||||
@@ -2023,10 +2029,10 @@ extension on TranslationsDe {
|
||||
'watchTogether.leave' => 'Verlassen',
|
||||
'watchTogether.syncing' => 'Synchronisieren...',
|
||||
'watchTogether.joinWatchSession' => 'Schausitzung Beitreten',
|
||||
'watchTogether.enterCodeHint' => '8-stelligen Code eingeben',
|
||||
'watchTogether.enterCodeHint' => '5-stelligen Code eingeben',
|
||||
'watchTogether.pasteFromClipboard' => 'Aus Zwischenablage einfügen',
|
||||
'watchTogether.pleaseEnterCode' => 'Bitte gib einen Sitzungscode ein',
|
||||
'watchTogether.codeMustBe8Chars' => 'Sitzungscode muss 8 Zeichen haben',
|
||||
'watchTogether.codeMustBe5Chars' => 'Sitzungscode muss 5 Zeichen haben',
|
||||
'watchTogether.joinInstructions' => 'Gib den vom Host geteilten Sitzungscode ein, um seiner Schausitzung beizutreten.',
|
||||
'watchTogether.failedToCreate' => 'Sitzung konnte nicht erstellt werden',
|
||||
'watchTogether.failedToJoin' => 'Sitzung konnte nicht beigetreten werden',
|
||||
@@ -2039,6 +2045,12 @@ extension on TranslationsDe {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Aktuelle Wiedergabe konnte nicht geöffnet werden',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} ist beigetreten',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} hat die Sitzung verlassen',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} hat pausiert',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} hat fortgesetzt',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} hat gespult',
|
||||
'watchTogether.recentRooms' => 'Letzte Räume',
|
||||
'watchTogether.renameRoom' => 'Raum umbenennen',
|
||||
'watchTogether.removeRoom' => 'Entfernen',
|
||||
'shaders.title' => 'Shader',
|
||||
'shaders.noShaderDescription' => 'Keine Videoverbesserung',
|
||||
'shaders.nvscalerDescription' => 'NVIDIA-Bildskalierung für schärferes Video',
|
||||
|
||||
@@ -2156,8 +2156,8 @@ class TranslationsWatchTogetherEn {
|
||||
/// en: 'Join Watch Session'
|
||||
String get joinWatchSession => 'Join Watch Session';
|
||||
|
||||
/// en: 'Enter 8-character code'
|
||||
String get enterCodeHint => 'Enter 8-character code';
|
||||
/// en: 'Enter 5-character code'
|
||||
String get enterCodeHint => 'Enter 5-character code';
|
||||
|
||||
/// en: 'Paste from clipboard'
|
||||
String get pasteFromClipboard => 'Paste from clipboard';
|
||||
@@ -2165,8 +2165,8 @@ class TranslationsWatchTogetherEn {
|
||||
/// en: 'Please enter a session code'
|
||||
String get pleaseEnterCode => 'Please enter a session code';
|
||||
|
||||
/// en: 'Session code must be 8 characters'
|
||||
String get codeMustBe8Chars => 'Session code must be 8 characters';
|
||||
/// en: 'Session code must be 5 characters'
|
||||
String get codeMustBe5Chars => 'Session code must be 5 characters';
|
||||
|
||||
/// en: 'Enter the session code shared by the host to join their watch session.'
|
||||
String get joinInstructions => 'Enter the session code shared by the host to join their watch session.';
|
||||
@@ -2203,6 +2203,24 @@ class TranslationsWatchTogetherEn {
|
||||
|
||||
/// en: '${name} left'
|
||||
String participantLeft({required Object name}) => '${name} left';
|
||||
|
||||
/// en: '${name} paused'
|
||||
String participantPaused({required Object name}) => '${name} paused';
|
||||
|
||||
/// en: '${name} resumed'
|
||||
String participantResumed({required Object name}) => '${name} resumed';
|
||||
|
||||
/// en: '${name} seeked'
|
||||
String participantSeeked({required Object name}) => '${name} seeked';
|
||||
|
||||
/// en: 'Recent Rooms'
|
||||
String get recentRooms => 'Recent Rooms';
|
||||
|
||||
/// en: 'Rename Room'
|
||||
String get renameRoom => 'Rename Room';
|
||||
|
||||
/// en: 'Remove'
|
||||
String get removeRoom => 'Remove';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -3735,10 +3753,10 @@ extension on Translations {
|
||||
'watchTogether.leave' => 'Leave',
|
||||
'watchTogether.syncing' => 'Syncing...',
|
||||
'watchTogether.joinWatchSession' => 'Join Watch Session',
|
||||
'watchTogether.enterCodeHint' => 'Enter 8-character code',
|
||||
'watchTogether.enterCodeHint' => 'Enter 5-character code',
|
||||
'watchTogether.pasteFromClipboard' => 'Paste from clipboard',
|
||||
'watchTogether.pleaseEnterCode' => 'Please enter a session code',
|
||||
'watchTogether.codeMustBe8Chars' => 'Session code must be 8 characters',
|
||||
'watchTogether.codeMustBe5Chars' => 'Session code must be 5 characters',
|
||||
'watchTogether.joinInstructions' => 'Enter the session code shared by the host to join their watch session.',
|
||||
'watchTogether.failedToCreate' => 'Failed to create session',
|
||||
'watchTogether.failedToJoin' => 'Failed to join session',
|
||||
@@ -3751,6 +3769,12 @@ extension on Translations {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Failed to open current playback',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} joined',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} left',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} paused',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} resumed',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} seeked',
|
||||
'watchTogether.recentRooms' => 'Recent Rooms',
|
||||
'watchTogether.renameRoom' => 'Rename Room',
|
||||
'watchTogether.removeRoom' => 'Remove',
|
||||
'downloads.title' => 'Downloads',
|
||||
'downloads.manage' => 'Manage',
|
||||
'downloads.tvShows' => 'TV Shows',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherEs implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Salir';
|
||||
@override String get syncing => 'Sincronizando...';
|
||||
@override String get joinWatchSession => 'Unirse a Sesión de Visualización';
|
||||
@override String get enterCodeHint => 'Introduce el código de 8 caracteres';
|
||||
@override String get enterCodeHint => 'Introduce el código de 5 caracteres';
|
||||
@override String get pasteFromClipboard => 'Pegar desde el portapapeles';
|
||||
@override String get pleaseEnterCode => 'Por favor, introduce un código de sesión';
|
||||
@override String get codeMustBe8Chars => 'El código de sesión debe tener 8 caracteres';
|
||||
@override String get codeMustBe5Chars => 'El código de sesión debe tener 5 caracteres';
|
||||
@override String get joinInstructions => 'Introduce el código de sesión compartido por el anfitrión para unirte a su sesión.';
|
||||
@override String get failedToCreate => 'Error al crear la sesión';
|
||||
@override String get failedToJoin => 'Error al unirse a la sesión';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherEs implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'No se pudo abrir la reproducción actual';
|
||||
@override String participantJoined({required Object name}) => '${name} se unió';
|
||||
@override String participantLeft({required Object name}) => '${name} se fue';
|
||||
@override String participantPaused({required Object name}) => '${name} pausó';
|
||||
@override String participantResumed({required Object name}) => '${name} reanudó';
|
||||
@override String participantSeeked({required Object name}) => '${name} avanzó';
|
||||
@override String get recentRooms => 'Salas recientes';
|
||||
@override String get renameRoom => 'Renombrar sala';
|
||||
@override String get removeRoom => 'Eliminar';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsEs {
|
||||
'watchTogether.leave' => 'Salir',
|
||||
'watchTogether.syncing' => 'Sincronizando...',
|
||||
'watchTogether.joinWatchSession' => 'Unirse a Sesión de Visualización',
|
||||
'watchTogether.enterCodeHint' => 'Introduce el código de 8 caracteres',
|
||||
'watchTogether.enterCodeHint' => 'Introduce el código de 5 caracteres',
|
||||
'watchTogether.pasteFromClipboard' => 'Pegar desde el portapapeles',
|
||||
'watchTogether.pleaseEnterCode' => 'Por favor, introduce un código de sesión',
|
||||
'watchTogether.codeMustBe8Chars' => 'El código de sesión debe tener 8 caracteres',
|
||||
'watchTogether.codeMustBe5Chars' => 'El código de sesión debe tener 5 caracteres',
|
||||
'watchTogether.joinInstructions' => 'Introduce el código de sesión compartido por el anfitrión para unirte a su sesión.',
|
||||
'watchTogether.failedToCreate' => 'Error al crear la sesión',
|
||||
'watchTogether.failedToJoin' => 'Error al unirse a la sesión',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsEs {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'No se pudo abrir la reproducción actual',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} se unió',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} se fue',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} pausó',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} reanudó',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} avanzó',
|
||||
'watchTogether.recentRooms' => 'Salas recientes',
|
||||
'watchTogether.renameRoom' => 'Renombrar sala',
|
||||
'watchTogether.removeRoom' => 'Eliminar',
|
||||
'downloads.title' => 'Descargas',
|
||||
'downloads.manage' => 'Gestionar',
|
||||
'downloads.tvShows' => 'Series de TV',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherFr implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Fin';
|
||||
@override String get syncing => 'Synchronisation...';
|
||||
@override String get joinWatchSession => 'Rejoindre la session de visionnage';
|
||||
@override String get enterCodeHint => 'Entrez le code à 8 caractères';
|
||||
@override String get enterCodeHint => 'Entrez le code à 5 caractères';
|
||||
@override String get pasteFromClipboard => 'Coller depuis le presse-papiers';
|
||||
@override String get pleaseEnterCode => 'Veuillez saisir un code de session';
|
||||
@override String get codeMustBe8Chars => 'Le code de session doit comporter 8 caractères';
|
||||
@override String get codeMustBe5Chars => 'Le code de session doit comporter 5 caractères';
|
||||
@override String get joinInstructions => 'Entrez le code de session partagé par l\'hôte pour rejoindre sa session de visionnage.';
|
||||
@override String get failedToCreate => 'Échec de la création de la session';
|
||||
@override String get failedToJoin => 'Échec de la connexion à la session';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherFr implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Impossible d\'ouvrir la lecture en cours';
|
||||
@override String participantJoined({required Object name}) => '${name} a rejoint';
|
||||
@override String participantLeft({required Object name}) => '${name} est parti';
|
||||
@override String participantPaused({required Object name}) => '${name} a mis en pause';
|
||||
@override String participantResumed({required Object name}) => '${name} a repris';
|
||||
@override String participantSeeked({required Object name}) => '${name} a avancé';
|
||||
@override String get recentRooms => 'Salons récents';
|
||||
@override String get renameRoom => 'Renommer le salon';
|
||||
@override String get removeRoom => 'Supprimer';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsFr {
|
||||
'watchTogether.leave' => 'Fin',
|
||||
'watchTogether.syncing' => 'Synchronisation...',
|
||||
'watchTogether.joinWatchSession' => 'Rejoindre la session de visionnage',
|
||||
'watchTogether.enterCodeHint' => 'Entrez le code à 8 caractères',
|
||||
'watchTogether.enterCodeHint' => 'Entrez le code à 5 caractères',
|
||||
'watchTogether.pasteFromClipboard' => 'Coller depuis le presse-papiers',
|
||||
'watchTogether.pleaseEnterCode' => 'Veuillez saisir un code de session',
|
||||
'watchTogether.codeMustBe8Chars' => 'Le code de session doit comporter 8 caractères',
|
||||
'watchTogether.codeMustBe5Chars' => 'Le code de session doit comporter 5 caractères',
|
||||
'watchTogether.joinInstructions' => 'Entrez le code de session partagé par l\'hôte pour rejoindre sa session de visionnage.',
|
||||
'watchTogether.failedToCreate' => 'Échec de la création de la session',
|
||||
'watchTogether.failedToJoin' => 'Échec de la connexion à la session',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsFr {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Impossible d\'ouvrir la lecture en cours',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} a rejoint',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} est parti',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} a mis en pause',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} a repris',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} a avancé',
|
||||
'watchTogether.recentRooms' => 'Salons récents',
|
||||
'watchTogether.renameRoom' => 'Renommer le salon',
|
||||
'watchTogether.removeRoom' => 'Supprimer',
|
||||
'downloads.title' => 'Téléchargements',
|
||||
'downloads.manage' => 'Gérer',
|
||||
'downloads.tvShows' => 'Show TV',
|
||||
|
||||
@@ -989,10 +989,10 @@ class _TranslationsWatchTogetherIt implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Lascia';
|
||||
@override String get syncing => 'Sincronizzazione...';
|
||||
@override String get joinWatchSession => 'Unisciti alla Sessione di Visione';
|
||||
@override String get enterCodeHint => 'Inserisci codice di 8 caratteri';
|
||||
@override String get enterCodeHint => 'Inserisci codice di 5 caratteri';
|
||||
@override String get pasteFromClipboard => 'Incolla dagli appunti';
|
||||
@override String get pleaseEnterCode => 'Inserisci un codice sessione';
|
||||
@override String get codeMustBe8Chars => 'Il codice sessione deve essere di 8 caratteri';
|
||||
@override String get codeMustBe5Chars => 'Il codice sessione deve essere di 5 caratteri';
|
||||
@override String get joinInstructions => 'Inserisci il codice sessione condiviso dall\'host per unirti alla loro sessione di visione.';
|
||||
@override String get failedToCreate => 'Impossibile creare la sessione';
|
||||
@override String get failedToJoin => 'Impossibile unirsi alla sessione';
|
||||
@@ -1005,6 +1005,12 @@ class _TranslationsWatchTogetherIt implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Impossibile aprire la riproduzione corrente';
|
||||
@override String participantJoined({required Object name}) => '${name} si è unito';
|
||||
@override String participantLeft({required Object name}) => '${name} se ne è andato';
|
||||
@override String participantPaused({required Object name}) => '${name} ha messo in pausa';
|
||||
@override String participantResumed({required Object name}) => '${name} ha ripreso';
|
||||
@override String participantSeeked({required Object name}) => '${name} ha cercato';
|
||||
@override String get recentRooms => 'Stanze recenti';
|
||||
@override String get renameRoom => 'Rinomina stanza';
|
||||
@override String get removeRoom => 'Rimuovi';
|
||||
}
|
||||
|
||||
// Path: shaders
|
||||
@@ -2023,10 +2029,10 @@ extension on TranslationsIt {
|
||||
'watchTogether.leave' => 'Lascia',
|
||||
'watchTogether.syncing' => 'Sincronizzazione...',
|
||||
'watchTogether.joinWatchSession' => 'Unisciti alla Sessione di Visione',
|
||||
'watchTogether.enterCodeHint' => 'Inserisci codice di 8 caratteri',
|
||||
'watchTogether.enterCodeHint' => 'Inserisci codice di 5 caratteri',
|
||||
'watchTogether.pasteFromClipboard' => 'Incolla dagli appunti',
|
||||
'watchTogether.pleaseEnterCode' => 'Inserisci un codice sessione',
|
||||
'watchTogether.codeMustBe8Chars' => 'Il codice sessione deve essere di 8 caratteri',
|
||||
'watchTogether.codeMustBe5Chars' => 'Il codice sessione deve essere di 5 caratteri',
|
||||
'watchTogether.joinInstructions' => 'Inserisci il codice sessione condiviso dall\'host per unirti alla loro sessione di visione.',
|
||||
'watchTogether.failedToCreate' => 'Impossibile creare la sessione',
|
||||
'watchTogether.failedToJoin' => 'Impossibile unirsi alla sessione',
|
||||
@@ -2039,6 +2045,12 @@ extension on TranslationsIt {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Impossibile aprire la riproduzione corrente',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} si è unito',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} se ne è andato',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} ha messo in pausa',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} ha ripreso',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} ha cercato',
|
||||
'watchTogether.recentRooms' => 'Stanze recenti',
|
||||
'watchTogether.renameRoom' => 'Rinomina stanza',
|
||||
'watchTogether.removeRoom' => 'Rimuovi',
|
||||
'shaders.title' => 'Shader',
|
||||
'shaders.noShaderDescription' => 'Nessun miglioramento video',
|
||||
'shaders.nvscalerDescription' => 'Ridimensionamento NVIDIA per video più nitido',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherJa implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => '退出';
|
||||
@override String get syncing => '同期中...';
|
||||
@override String get joinWatchSession => '視聴セッションに参加';
|
||||
@override String get enterCodeHint => '8文字のコードを入力';
|
||||
@override String get enterCodeHint => '5文字のコードを入力';
|
||||
@override String get pasteFromClipboard => 'クリップボードから貼り付け';
|
||||
@override String get pleaseEnterCode => 'セッションコードを入力してください';
|
||||
@override String get codeMustBe8Chars => 'セッションコードは8文字である必要があります';
|
||||
@override String get codeMustBe5Chars => 'セッションコードは5文字である必要があります';
|
||||
@override String get joinInstructions => 'ホストが共有したセッションコードを入力して視聴セッションに参加してください。';
|
||||
@override String get failedToCreate => 'セッションの作成に失敗しました';
|
||||
@override String get failedToJoin => 'セッションへの参加に失敗しました';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherJa implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => '現在の再生を開けませんでした';
|
||||
@override String participantJoined({required Object name}) => '${name}が参加しました';
|
||||
@override String participantLeft({required Object name}) => '${name}が退出しました';
|
||||
@override String participantPaused({required Object name}) => '${name}が一時停止しました';
|
||||
@override String participantResumed({required Object name}) => '${name}が再開しました';
|
||||
@override String participantSeeked({required Object name}) => '${name}がシークしました';
|
||||
@override String get recentRooms => '最近のルーム';
|
||||
@override String get renameRoom => 'ルーム名を変更';
|
||||
@override String get removeRoom => '削除';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsJa {
|
||||
'watchTogether.leave' => '退出',
|
||||
'watchTogether.syncing' => '同期中...',
|
||||
'watchTogether.joinWatchSession' => '視聴セッションに参加',
|
||||
'watchTogether.enterCodeHint' => '8文字のコードを入力',
|
||||
'watchTogether.enterCodeHint' => '5文字のコードを入力',
|
||||
'watchTogether.pasteFromClipboard' => 'クリップボードから貼り付け',
|
||||
'watchTogether.pleaseEnterCode' => 'セッションコードを入力してください',
|
||||
'watchTogether.codeMustBe8Chars' => 'セッションコードは8文字である必要があります',
|
||||
'watchTogether.codeMustBe5Chars' => 'セッションコードは5文字である必要があります',
|
||||
'watchTogether.joinInstructions' => 'ホストが共有したセッションコードを入力して視聴セッションに参加してください。',
|
||||
'watchTogether.failedToCreate' => 'セッションの作成に失敗しました',
|
||||
'watchTogether.failedToJoin' => 'セッションへの参加に失敗しました',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsJa {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => '現在の再生を開けませんでした',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name}が参加しました',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name}が退出しました',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name}が一時停止しました',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name}が再開しました',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name}がシークしました',
|
||||
'watchTogether.recentRooms' => '最近のルーム',
|
||||
'watchTogether.renameRoom' => 'ルーム名を変更',
|
||||
'watchTogether.removeRoom' => '削除',
|
||||
'downloads.title' => 'ダウンロード',
|
||||
'downloads.manage' => '管理',
|
||||
'downloads.tvShows' => 'テレビ番組',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherKo implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => '이탈';
|
||||
@override String get syncing => '동기화 중...';
|
||||
@override String get joinWatchSession => '시청 세션에 참여';
|
||||
@override String get enterCodeHint => '8자리 코드 입력';
|
||||
@override String get enterCodeHint => '5자리 코드 입력';
|
||||
@override String get pasteFromClipboard => '클립보드에서 붙여넣기';
|
||||
@override String get pleaseEnterCode => '세션 코드를 입력하세요';
|
||||
@override String get codeMustBe8Chars => '세션 코드는 반드시 8자리여야 합니다';
|
||||
@override String get codeMustBe5Chars => '세션 코드는 반드시 5자리여야 합니다';
|
||||
@override String get joinInstructions => '호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.';
|
||||
@override String get failedToCreate => '세션 생성 실패';
|
||||
@override String get failedToJoin => '세션 참여 실패';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherKo implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => '현재 재생을 열 수 없습니다';
|
||||
@override String participantJoined({required Object name}) => '${name}님이 참여했습니다';
|
||||
@override String participantLeft({required Object name}) => '${name}님이 나갔습니다';
|
||||
@override String participantPaused({required Object name}) => '${name}님이 일시정지했습니다';
|
||||
@override String participantResumed({required Object name}) => '${name}님이 재생했습니다';
|
||||
@override String participantSeeked({required Object name}) => '${name}님이 탐색했습니다';
|
||||
@override String get recentRooms => '최근 방';
|
||||
@override String get renameRoom => '방 이름 변경';
|
||||
@override String get removeRoom => '제거';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsKo {
|
||||
'watchTogether.leave' => '이탈',
|
||||
'watchTogether.syncing' => '동기화 중...',
|
||||
'watchTogether.joinWatchSession' => '시청 세션에 참여',
|
||||
'watchTogether.enterCodeHint' => '8자리 코드 입력',
|
||||
'watchTogether.enterCodeHint' => '5자리 코드 입력',
|
||||
'watchTogether.pasteFromClipboard' => '클립보드에서 붙여넣기',
|
||||
'watchTogether.pleaseEnterCode' => '세션 코드를 입력하세요',
|
||||
'watchTogether.codeMustBe8Chars' => '세션 코드는 반드시 8자리여야 합니다',
|
||||
'watchTogether.codeMustBe5Chars' => '세션 코드는 반드시 5자리여야 합니다',
|
||||
'watchTogether.joinInstructions' => '호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.',
|
||||
'watchTogether.failedToCreate' => '세션 생성 실패',
|
||||
'watchTogether.failedToJoin' => '세션 참여 실패',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsKo {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => '현재 재생을 열 수 없습니다',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name}님이 참여했습니다',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name}님이 나갔습니다',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name}님이 일시정지했습니다',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name}님이 재생했습니다',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name}님이 탐색했습니다',
|
||||
'watchTogether.recentRooms' => '최근 방',
|
||||
'watchTogether.renameRoom' => '방 이름 변경',
|
||||
'watchTogether.removeRoom' => '제거',
|
||||
'downloads.title' => '다운로드',
|
||||
'downloads.manage' => '관리',
|
||||
'downloads.tvShows' => 'TV 프로그램',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherNb implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Forlat';
|
||||
@override String get syncing => 'Synkroniserer...';
|
||||
@override String get joinWatchSession => 'Bli med i se sammen-økt';
|
||||
@override String get enterCodeHint => 'Skriv inn 8-tegns kode';
|
||||
@override String get enterCodeHint => 'Skriv inn 5-tegns kode';
|
||||
@override String get pasteFromClipboard => 'Lim inn fra utklippstavle';
|
||||
@override String get pleaseEnterCode => 'Vennligst skriv inn en øktkode';
|
||||
@override String get codeMustBe8Chars => 'Øktkoden må være 8 tegn';
|
||||
@override String get codeMustBe5Chars => 'Øktkoden må være 5 tegn';
|
||||
@override String get joinInstructions => 'Skriv inn øktkoden delt av verten for å bli med i se sammen-økten.';
|
||||
@override String get failedToCreate => 'Kunne ikke opprette økt';
|
||||
@override String get failedToJoin => 'Kunne ikke bli med i økt';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherNb implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Kunne ikke åpne gjeldende avspilling';
|
||||
@override String participantJoined({required Object name}) => '${name} ble med';
|
||||
@override String participantLeft({required Object name}) => '${name} forlot';
|
||||
@override String participantPaused({required Object name}) => '${name} pauset';
|
||||
@override String participantResumed({required Object name}) => '${name} gjenopptok';
|
||||
@override String participantSeeked({required Object name}) => '${name} spolet';
|
||||
@override String get recentRooms => 'Nylige rom';
|
||||
@override String get renameRoom => 'Gi nytt navn til rom';
|
||||
@override String get removeRoom => 'Fjern';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsNb {
|
||||
'watchTogether.leave' => 'Forlat',
|
||||
'watchTogether.syncing' => 'Synkroniserer...',
|
||||
'watchTogether.joinWatchSession' => 'Bli med i se sammen-økt',
|
||||
'watchTogether.enterCodeHint' => 'Skriv inn 8-tegns kode',
|
||||
'watchTogether.enterCodeHint' => 'Skriv inn 5-tegns kode',
|
||||
'watchTogether.pasteFromClipboard' => 'Lim inn fra utklippstavle',
|
||||
'watchTogether.pleaseEnterCode' => 'Vennligst skriv inn en øktkode',
|
||||
'watchTogether.codeMustBe8Chars' => 'Øktkoden må være 8 tegn',
|
||||
'watchTogether.codeMustBe5Chars' => 'Øktkoden må være 5 tegn',
|
||||
'watchTogether.joinInstructions' => 'Skriv inn øktkoden delt av verten for å bli med i se sammen-økten.',
|
||||
'watchTogether.failedToCreate' => 'Kunne ikke opprette økt',
|
||||
'watchTogether.failedToJoin' => 'Kunne ikke bli med i økt',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsNb {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Kunne ikke åpne gjeldende avspilling',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} ble med',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} forlot',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} pauset',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} gjenopptok',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} spolet',
|
||||
'watchTogether.recentRooms' => 'Nylige rom',
|
||||
'watchTogether.renameRoom' => 'Gi nytt navn til rom',
|
||||
'watchTogether.removeRoom' => 'Fjern',
|
||||
'downloads.title' => 'Nedlastinger',
|
||||
'downloads.manage' => 'Administrer',
|
||||
'downloads.tvShows' => 'TV-serier',
|
||||
|
||||
@@ -989,10 +989,10 @@ class _TranslationsWatchTogetherNl implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Verlaten';
|
||||
@override String get syncing => 'Synchroniseren...';
|
||||
@override String get joinWatchSession => 'Kijksessie Deelnemen';
|
||||
@override String get enterCodeHint => 'Voer 8-teken code in';
|
||||
@override String get enterCodeHint => 'Voer 5-teken code in';
|
||||
@override String get pasteFromClipboard => 'Plakken van klembord';
|
||||
@override String get pleaseEnterCode => 'Voer een sessiecode in';
|
||||
@override String get codeMustBe8Chars => 'Sessiecode moet 8 tekens zijn';
|
||||
@override String get codeMustBe5Chars => 'Sessiecode moet 5 tekens zijn';
|
||||
@override String get joinInstructions => 'Voer de sessiecode in die door de host is gedeeld om deel te nemen aan hun kijksessie.';
|
||||
@override String get failedToCreate => 'Sessie maken mislukt';
|
||||
@override String get failedToJoin => 'Sessie deelnemen mislukt';
|
||||
@@ -1005,6 +1005,12 @@ class _TranslationsWatchTogetherNl implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Huidige weergave kon niet worden geopend';
|
||||
@override String participantJoined({required Object name}) => '${name} is toegetreden';
|
||||
@override String participantLeft({required Object name}) => '${name} heeft de sessie verlaten';
|
||||
@override String participantPaused({required Object name}) => '${name} heeft gepauzeerd';
|
||||
@override String participantResumed({required Object name}) => '${name} heeft hervat';
|
||||
@override String participantSeeked({required Object name}) => '${name} heeft gespoeld';
|
||||
@override String get recentRooms => 'Recente kamers';
|
||||
@override String get renameRoom => 'Kamer hernoemen';
|
||||
@override String get removeRoom => 'Verwijderen';
|
||||
}
|
||||
|
||||
// Path: shaders
|
||||
@@ -2023,10 +2029,10 @@ extension on TranslationsNl {
|
||||
'watchTogether.leave' => 'Verlaten',
|
||||
'watchTogether.syncing' => 'Synchroniseren...',
|
||||
'watchTogether.joinWatchSession' => 'Kijksessie Deelnemen',
|
||||
'watchTogether.enterCodeHint' => 'Voer 8-teken code in',
|
||||
'watchTogether.enterCodeHint' => 'Voer 5-teken code in',
|
||||
'watchTogether.pasteFromClipboard' => 'Plakken van klembord',
|
||||
'watchTogether.pleaseEnterCode' => 'Voer een sessiecode in',
|
||||
'watchTogether.codeMustBe8Chars' => 'Sessiecode moet 8 tekens zijn',
|
||||
'watchTogether.codeMustBe5Chars' => 'Sessiecode moet 5 tekens zijn',
|
||||
'watchTogether.joinInstructions' => 'Voer de sessiecode in die door de host is gedeeld om deel te nemen aan hun kijksessie.',
|
||||
'watchTogether.failedToCreate' => 'Sessie maken mislukt',
|
||||
'watchTogether.failedToJoin' => 'Sessie deelnemen mislukt',
|
||||
@@ -2039,6 +2045,12 @@ extension on TranslationsNl {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Huidige weergave kon niet worden geopend',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} is toegetreden',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} heeft de sessie verlaten',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} heeft gepauzeerd',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} heeft hervat',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} heeft gespoeld',
|
||||
'watchTogether.recentRooms' => 'Recente kamers',
|
||||
'watchTogether.renameRoom' => 'Kamer hernoemen',
|
||||
'watchTogether.removeRoom' => 'Verwijderen',
|
||||
'shaders.title' => 'Shaders',
|
||||
'shaders.noShaderDescription' => 'Geen videoverbetering',
|
||||
'shaders.nvscalerDescription' => 'NVIDIA-beeldschaling voor scherpere video',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherPl implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Opuść';
|
||||
@override String get syncing => 'Synchronizacja...';
|
||||
@override String get joinWatchSession => 'Dołącz do sesji oglądania';
|
||||
@override String get enterCodeHint => 'Wprowadź 8-znakowy kod';
|
||||
@override String get enterCodeHint => 'Wprowadź 5-znakowy kod';
|
||||
@override String get pasteFromClipboard => 'Wklej ze schowka';
|
||||
@override String get pleaseEnterCode => 'Wprowadź kod sesji';
|
||||
@override String get codeMustBe8Chars => 'Kod sesji musi mieć 8 znaków';
|
||||
@override String get codeMustBe5Chars => 'Kod sesji musi mieć 5 znaków';
|
||||
@override String get joinInstructions => 'Wprowadź kod sesji udostępniony przez hosta, aby dołączyć do sesji oglądania.';
|
||||
@override String get failedToCreate => 'Nie udało się utworzyć sesji';
|
||||
@override String get failedToJoin => 'Nie udało się dołączyć do sesji';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherPl implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Nie udało się otworzyć bieżącego odtwarzania';
|
||||
@override String participantJoined({required Object name}) => '${name} dołączył';
|
||||
@override String participantLeft({required Object name}) => '${name} opuścił';
|
||||
@override String participantPaused({required Object name}) => '${name} wstrzymał';
|
||||
@override String participantResumed({required Object name}) => '${name} wznowił';
|
||||
@override String participantSeeked({required Object name}) => '${name} przewinął';
|
||||
@override String get recentRooms => 'Ostatnie pokoje';
|
||||
@override String get renameRoom => 'Zmień nazwę pokoju';
|
||||
@override String get removeRoom => 'Usuń';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsPl {
|
||||
'watchTogether.leave' => 'Opuść',
|
||||
'watchTogether.syncing' => 'Synchronizacja...',
|
||||
'watchTogether.joinWatchSession' => 'Dołącz do sesji oglądania',
|
||||
'watchTogether.enterCodeHint' => 'Wprowadź 8-znakowy kod',
|
||||
'watchTogether.enterCodeHint' => 'Wprowadź 5-znakowy kod',
|
||||
'watchTogether.pasteFromClipboard' => 'Wklej ze schowka',
|
||||
'watchTogether.pleaseEnterCode' => 'Wprowadź kod sesji',
|
||||
'watchTogether.codeMustBe8Chars' => 'Kod sesji musi mieć 8 znaków',
|
||||
'watchTogether.codeMustBe5Chars' => 'Kod sesji musi mieć 5 znaków',
|
||||
'watchTogether.joinInstructions' => 'Wprowadź kod sesji udostępniony przez hosta, aby dołączyć do sesji oglądania.',
|
||||
'watchTogether.failedToCreate' => 'Nie udało się utworzyć sesji',
|
||||
'watchTogether.failedToJoin' => 'Nie udało się dołączyć do sesji',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsPl {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Nie udało się otworzyć bieżącego odtwarzania',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} dołączył',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} opuścił',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} wstrzymał',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} wznowił',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} przewinął',
|
||||
'watchTogether.recentRooms' => 'Ostatnie pokoje',
|
||||
'watchTogether.renameRoom' => 'Zmień nazwę pokoju',
|
||||
'watchTogether.removeRoom' => 'Usuń',
|
||||
'downloads.title' => 'Pobrania',
|
||||
'downloads.manage' => 'Zarządzaj',
|
||||
'downloads.tvShows' => 'Seriale TV',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherPt implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Sair';
|
||||
@override String get syncing => 'Sincronizando...';
|
||||
@override String get joinWatchSession => 'Entrar na Sessão';
|
||||
@override String get enterCodeHint => 'Insira o código de 8 caracteres';
|
||||
@override String get enterCodeHint => 'Insira o código de 5 caracteres';
|
||||
@override String get pasteFromClipboard => 'Colar da área de transferência';
|
||||
@override String get pleaseEnterCode => 'Insira um código de sessão';
|
||||
@override String get codeMustBe8Chars => 'O código da sessão deve ter 8 caracteres';
|
||||
@override String get codeMustBe5Chars => 'O código da sessão deve ter 5 caracteres';
|
||||
@override String get joinInstructions => 'Insira o código da sessão compartilhado pelo anfitrião para entrar na sessão.';
|
||||
@override String get failedToCreate => 'Falha ao criar sessão';
|
||||
@override String get failedToJoin => 'Falha ao entrar na sessão';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherPt implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Falha ao abrir reprodução atual';
|
||||
@override String participantJoined({required Object name}) => '${name} entrou';
|
||||
@override String participantLeft({required Object name}) => '${name} saiu';
|
||||
@override String participantPaused({required Object name}) => '${name} pausou';
|
||||
@override String participantResumed({required Object name}) => '${name} retomou';
|
||||
@override String participantSeeked({required Object name}) => '${name} avançou';
|
||||
@override String get recentRooms => 'Salas recentes';
|
||||
@override String get renameRoom => 'Renomear sala';
|
||||
@override String get removeRoom => 'Remover';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsPt {
|
||||
'watchTogether.leave' => 'Sair',
|
||||
'watchTogether.syncing' => 'Sincronizando...',
|
||||
'watchTogether.joinWatchSession' => 'Entrar na Sessão',
|
||||
'watchTogether.enterCodeHint' => 'Insira o código de 8 caracteres',
|
||||
'watchTogether.enterCodeHint' => 'Insira o código de 5 caracteres',
|
||||
'watchTogether.pasteFromClipboard' => 'Colar da área de transferência',
|
||||
'watchTogether.pleaseEnterCode' => 'Insira um código de sessão',
|
||||
'watchTogether.codeMustBe8Chars' => 'O código da sessão deve ter 8 caracteres',
|
||||
'watchTogether.codeMustBe5Chars' => 'O código da sessão deve ter 5 caracteres',
|
||||
'watchTogether.joinInstructions' => 'Insira o código da sessão compartilhado pelo anfitrião para entrar na sessão.',
|
||||
'watchTogether.failedToCreate' => 'Falha ao criar sessão',
|
||||
'watchTogether.failedToJoin' => 'Falha ao entrar na sessão',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsPt {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Falha ao abrir reprodução atual',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} entrou',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} saiu',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} pausou',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} retomou',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} avançou',
|
||||
'watchTogether.recentRooms' => 'Salas recentes',
|
||||
'watchTogether.renameRoom' => 'Renomear sala',
|
||||
'watchTogether.removeRoom' => 'Remover',
|
||||
'downloads.title' => 'Downloads',
|
||||
'downloads.manage' => 'Gerenciar',
|
||||
'downloads.tvShows' => 'Séries de TV',
|
||||
|
||||
@@ -955,10 +955,10 @@ class _TranslationsWatchTogetherRu implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Покинуть';
|
||||
@override String get syncing => 'Синхронизация...';
|
||||
@override String get joinWatchSession => 'Присоединиться к просмотру';
|
||||
@override String get enterCodeHint => 'Введите 8-символьный код';
|
||||
@override String get enterCodeHint => 'Введите 5-символьный код';
|
||||
@override String get pasteFromClipboard => 'Вставить из буфера обмена';
|
||||
@override String get pleaseEnterCode => 'Введите код сессии';
|
||||
@override String get codeMustBe8Chars => 'Код сессии должен содержать 8 символов';
|
||||
@override String get codeMustBe5Chars => 'Код сессии должен содержать 5 символов';
|
||||
@override String get joinInstructions => 'Введите код сессии, предоставленный хостом, чтобы присоединиться к просмотру.';
|
||||
@override String get failedToCreate => 'Не удалось создать сессию';
|
||||
@override String get failedToJoin => 'Не удалось присоединиться к сессии';
|
||||
@@ -971,6 +971,12 @@ class _TranslationsWatchTogetherRu implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Не удалось открыть текущее воспроизведение';
|
||||
@override String participantJoined({required Object name}) => '${name} присоединился';
|
||||
@override String participantLeft({required Object name}) => '${name} вышел';
|
||||
@override String participantPaused({required Object name}) => '${name} поставил на паузу';
|
||||
@override String participantResumed({required Object name}) => '${name} возобновил';
|
||||
@override String participantSeeked({required Object name}) => '${name} перемотал';
|
||||
@override String get recentRooms => 'Недавние комнаты';
|
||||
@override String get renameRoom => 'Переименовать комнату';
|
||||
@override String get removeRoom => 'Удалить';
|
||||
}
|
||||
|
||||
// Path: downloads
|
||||
@@ -1998,10 +2004,10 @@ extension on TranslationsRu {
|
||||
'watchTogether.leave' => 'Покинуть',
|
||||
'watchTogether.syncing' => 'Синхронизация...',
|
||||
'watchTogether.joinWatchSession' => 'Присоединиться к просмотру',
|
||||
'watchTogether.enterCodeHint' => 'Введите 8-символьный код',
|
||||
'watchTogether.enterCodeHint' => 'Введите 5-символьный код',
|
||||
'watchTogether.pasteFromClipboard' => 'Вставить из буфера обмена',
|
||||
'watchTogether.pleaseEnterCode' => 'Введите код сессии',
|
||||
'watchTogether.codeMustBe8Chars' => 'Код сессии должен содержать 8 символов',
|
||||
'watchTogether.codeMustBe5Chars' => 'Код сессии должен содержать 5 символов',
|
||||
'watchTogether.joinInstructions' => 'Введите код сессии, предоставленный хостом, чтобы присоединиться к просмотру.',
|
||||
'watchTogether.failedToCreate' => 'Не удалось создать сессию',
|
||||
'watchTogether.failedToJoin' => 'Не удалось присоединиться к сессии',
|
||||
@@ -2014,6 +2020,12 @@ extension on TranslationsRu {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Не удалось открыть текущее воспроизведение',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} присоединился',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} вышел',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} поставил на паузу',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} возобновил',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} перемотал',
|
||||
'watchTogether.recentRooms' => 'Недавние комнаты',
|
||||
'watchTogether.renameRoom' => 'Переименовать комнату',
|
||||
'watchTogether.removeRoom' => 'Удалить',
|
||||
'downloads.title' => 'Загрузки',
|
||||
'downloads.manage' => 'Управление',
|
||||
'downloads.tvShows' => 'Сериалы',
|
||||
|
||||
@@ -989,10 +989,10 @@ class _TranslationsWatchTogetherSv implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => 'Lämna';
|
||||
@override String get syncing => 'Synkroniserar...';
|
||||
@override String get joinWatchSession => 'Gå med i Tittarsession';
|
||||
@override String get enterCodeHint => 'Ange 8-teckens kod';
|
||||
@override String get enterCodeHint => 'Ange 5-teckens kod';
|
||||
@override String get pasteFromClipboard => 'Klistra in från urklipp';
|
||||
@override String get pleaseEnterCode => 'Vänligen ange en sessionskod';
|
||||
@override String get codeMustBe8Chars => 'Sessionskod måste vara 8 tecken';
|
||||
@override String get codeMustBe5Chars => 'Sessionskod måste vara 5 tecken';
|
||||
@override String get joinInstructions => 'Ange sessionskoden som delats av värden för att gå med i deras tittarsession.';
|
||||
@override String get failedToCreate => 'Det gick inte att skapa session';
|
||||
@override String get failedToJoin => 'Det gick inte att gå med i session';
|
||||
@@ -1005,6 +1005,12 @@ class _TranslationsWatchTogetherSv implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => 'Kunde inte öppna aktuell uppspelning';
|
||||
@override String participantJoined({required Object name}) => '${name} gick med';
|
||||
@override String participantLeft({required Object name}) => '${name} lämnade';
|
||||
@override String participantPaused({required Object name}) => '${name} pausade';
|
||||
@override String participantResumed({required Object name}) => '${name} återupptog';
|
||||
@override String participantSeeked({required Object name}) => '${name} spolade';
|
||||
@override String get recentRooms => 'Senaste rum';
|
||||
@override String get renameRoom => 'Byt namn på rum';
|
||||
@override String get removeRoom => 'Ta bort';
|
||||
}
|
||||
|
||||
// Path: shaders
|
||||
@@ -2023,10 +2029,10 @@ extension on TranslationsSv {
|
||||
'watchTogether.leave' => 'Lämna',
|
||||
'watchTogether.syncing' => 'Synkroniserar...',
|
||||
'watchTogether.joinWatchSession' => 'Gå med i Tittarsession',
|
||||
'watchTogether.enterCodeHint' => 'Ange 8-teckens kod',
|
||||
'watchTogether.enterCodeHint' => 'Ange 5-teckens kod',
|
||||
'watchTogether.pasteFromClipboard' => 'Klistra in från urklipp',
|
||||
'watchTogether.pleaseEnterCode' => 'Vänligen ange en sessionskod',
|
||||
'watchTogether.codeMustBe8Chars' => 'Sessionskod måste vara 8 tecken',
|
||||
'watchTogether.codeMustBe5Chars' => 'Sessionskod måste vara 5 tecken',
|
||||
'watchTogether.joinInstructions' => 'Ange sessionskoden som delats av värden för att gå med i deras tittarsession.',
|
||||
'watchTogether.failedToCreate' => 'Det gick inte att skapa session',
|
||||
'watchTogether.failedToJoin' => 'Det gick inte att gå med i session',
|
||||
@@ -2039,6 +2045,12 @@ extension on TranslationsSv {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => 'Kunde inte öppna aktuell uppspelning',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} gick med',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} lämnade',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} pausade',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} återupptog',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} spolade',
|
||||
'watchTogether.recentRooms' => 'Senaste rum',
|
||||
'watchTogether.renameRoom' => 'Byt namn på rum',
|
||||
'watchTogether.removeRoom' => 'Ta bort',
|
||||
'shaders.title' => 'Shaders',
|
||||
'shaders.noShaderDescription' => 'Ingen videoförbättring',
|
||||
'shaders.nvscalerDescription' => 'NVIDIA-bildskalning för skarpare video',
|
||||
|
||||
@@ -989,10 +989,10 @@ class _TranslationsWatchTogetherZh implements TranslationsWatchTogetherEn {
|
||||
@override String get leave => '离开';
|
||||
@override String get syncing => '同步中...';
|
||||
@override String get joinWatchSession => '加入观看会话';
|
||||
@override String get enterCodeHint => '输入8位代码';
|
||||
@override String get enterCodeHint => '输入5位代码';
|
||||
@override String get pasteFromClipboard => '从剪贴板粘贴';
|
||||
@override String get pleaseEnterCode => '请输入会话代码';
|
||||
@override String get codeMustBe8Chars => '会话代码必须是8个字符';
|
||||
@override String get codeMustBe5Chars => '会话代码必须是5个字符';
|
||||
@override String get joinInstructions => '输入主持人分享的会话代码以加入他们的观看会话。';
|
||||
@override String get failedToCreate => '创建会话失败';
|
||||
@override String get failedToJoin => '加入会话失败';
|
||||
@@ -1005,6 +1005,12 @@ class _TranslationsWatchTogetherZh implements TranslationsWatchTogetherEn {
|
||||
@override String get failedToOpenCurrentPlayback => '无法打开当前播放';
|
||||
@override String participantJoined({required Object name}) => '${name} 加入了';
|
||||
@override String participantLeft({required Object name}) => '${name} 离开了';
|
||||
@override String participantPaused({required Object name}) => '${name} 暂停了';
|
||||
@override String participantResumed({required Object name}) => '${name} 继续播放了';
|
||||
@override String participantSeeked({required Object name}) => '${name} 跳转了';
|
||||
@override String get recentRooms => '最近的房间';
|
||||
@override String get renameRoom => '重命名房间';
|
||||
@override String get removeRoom => '移除';
|
||||
}
|
||||
|
||||
// Path: shaders
|
||||
@@ -2023,10 +2029,10 @@ extension on TranslationsZh {
|
||||
'watchTogether.leave' => '离开',
|
||||
'watchTogether.syncing' => '同步中...',
|
||||
'watchTogether.joinWatchSession' => '加入观看会话',
|
||||
'watchTogether.enterCodeHint' => '输入8位代码',
|
||||
'watchTogether.enterCodeHint' => '输入5位代码',
|
||||
'watchTogether.pasteFromClipboard' => '从剪贴板粘贴',
|
||||
'watchTogether.pleaseEnterCode' => '请输入会话代码',
|
||||
'watchTogether.codeMustBe8Chars' => '会话代码必须是8个字符',
|
||||
'watchTogether.codeMustBe5Chars' => '会话代码必须是5个字符',
|
||||
'watchTogether.joinInstructions' => '输入主持人分享的会话代码以加入他们的观看会话。',
|
||||
'watchTogether.failedToCreate' => '创建会话失败',
|
||||
'watchTogether.failedToJoin' => '加入会话失败',
|
||||
@@ -2039,6 +2045,12 @@ extension on TranslationsZh {
|
||||
'watchTogether.failedToOpenCurrentPlayback' => '无法打开当前播放',
|
||||
'watchTogether.participantJoined' => ({required Object name}) => '${name} 加入了',
|
||||
'watchTogether.participantLeft' => ({required Object name}) => '${name} 离开了',
|
||||
'watchTogether.participantPaused' => ({required Object name}) => '${name} 暂停了',
|
||||
'watchTogether.participantResumed' => ({required Object name}) => '${name} 继续播放了',
|
||||
'watchTogether.participantSeeked' => ({required Object name}) => '${name} 跳转了',
|
||||
'watchTogether.recentRooms' => '最近的房间',
|
||||
'watchTogether.renameRoom' => '重命名房间',
|
||||
'watchTogether.removeRoom' => '移除',
|
||||
'shaders.title' => '着色器',
|
||||
'shaders.noShaderDescription' => '无视频增强',
|
||||
'shaders.nvscalerDescription' => 'NVIDIA 图像缩放,使视频更清晰',
|
||||
|
||||
@@ -729,10 +729,10 @@
|
||||
"leave": "Lämna",
|
||||
"syncing": "Synkroniserar...",
|
||||
"joinWatchSession": "Gå med i Tittarsession",
|
||||
"enterCodeHint": "Ange 8-teckens kod",
|
||||
"enterCodeHint": "Ange 5-teckens kod",
|
||||
"pasteFromClipboard": "Klistra in från urklipp",
|
||||
"pleaseEnterCode": "Vänligen ange en sessionskod",
|
||||
"codeMustBe8Chars": "Sessionskod måste vara 8 tecken",
|
||||
"codeMustBe5Chars": "Sessionskod måste vara 5 tecken",
|
||||
"joinInstructions": "Ange sessionskoden som delats av värden för att gå med i deras tittarsession.",
|
||||
"failedToCreate": "Det gick inte att skapa session",
|
||||
"failedToJoin": "Det gick inte att gå med i session",
|
||||
@@ -744,7 +744,13 @@
|
||||
"joinCurrentPlaybackDescription": "Hoppa tillbaka till det värden tittar på just nu",
|
||||
"failedToOpenCurrentPlayback": "Kunde inte öppna aktuell uppspelning",
|
||||
"participantJoined": "${name} gick med",
|
||||
"participantLeft": "${name} lämnade"
|
||||
"participantLeft": "${name} lämnade",
|
||||
"participantPaused": "${name} pausade",
|
||||
"participantResumed": "${name} återupptog",
|
||||
"participantSeeked": "${name} spolade",
|
||||
"recentRooms": "Senaste rum",
|
||||
"renameRoom": "Byt namn på rum",
|
||||
"removeRoom": "Ta bort"
|
||||
},
|
||||
"shaders": {
|
||||
"title": "Shaders",
|
||||
|
||||
@@ -729,10 +729,10 @@
|
||||
"leave": "离开",
|
||||
"syncing": "同步中...",
|
||||
"joinWatchSession": "加入观看会话",
|
||||
"enterCodeHint": "输入8位代码",
|
||||
"enterCodeHint": "输入5位代码",
|
||||
"pasteFromClipboard": "从剪贴板粘贴",
|
||||
"pleaseEnterCode": "请输入会话代码",
|
||||
"codeMustBe8Chars": "会话代码必须是8个字符",
|
||||
"codeMustBe5Chars": "会话代码必须是5个字符",
|
||||
"joinInstructions": "输入主持人分享的会话代码以加入他们的观看会话。",
|
||||
"failedToCreate": "创建会话失败",
|
||||
"failedToJoin": "加入会话失败",
|
||||
@@ -744,7 +744,13 @@
|
||||
"joinCurrentPlaybackDescription": "回到房主当前正在观看的内容",
|
||||
"failedToOpenCurrentPlayback": "无法打开当前播放",
|
||||
"participantJoined": "${name} 加入了",
|
||||
"participantLeft": "${name} 离开了"
|
||||
"participantLeft": "${name} 离开了",
|
||||
"participantPaused": "${name} 暂停了",
|
||||
"participantResumed": "${name} 继续播放了",
|
||||
"participantSeeked": "${name} 跳转了",
|
||||
"recentRooms": "最近的房间",
|
||||
"renameRoom": "重命名房间",
|
||||
"removeRoom": "移除"
|
||||
},
|
||||
"shaders": {
|
||||
"title": "着色器",
|
||||
|
||||
@@ -113,6 +113,7 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
static const String _keyCustomShaderPresets = 'custom_shader_presets';
|
||||
static const String _keyLiveTvDefaultFavorites = 'live_tv_default_favorites';
|
||||
static const String _keyCustomRelayUrl = 'custom_relay_url';
|
||||
static const String _keyRecentRooms = 'watch_together_recent_rooms';
|
||||
static const String _keyMatchRefreshRate = 'match_refresh_rate';
|
||||
static const String _keyMatchDynamicRange = 'match_dynamic_range';
|
||||
static const String _keyDisplaySwitchDelay = 'display_switch_delay';
|
||||
@@ -938,6 +939,15 @@ class SettingsService extends BaseSharedPreferencesService {
|
||||
return prefs.getString(_keyCustomRelayUrl);
|
||||
}
|
||||
|
||||
// Recent Watch Together rooms
|
||||
Future<void> setRecentRooms(String json) async {
|
||||
await prefs.setString(_keyRecentRooms, json);
|
||||
}
|
||||
|
||||
String? getRecentRooms() {
|
||||
return prefs.getString(_keyRecentRooms);
|
||||
}
|
||||
|
||||
// Download on WiFi Only
|
||||
Future<void> setDownloadOnWifiOnly(bool value) async {
|
||||
await prefs.setBool(_keyDownloadOnWifiOnly, value);
|
||||
|
||||
@@ -50,6 +50,9 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
Timer? _hostReconnectTimer;
|
||||
bool _isWaitingForHostReconnect = false;
|
||||
|
||||
// Debounce map for action events (peerId+type → last emission timestamp)
|
||||
final Map<String, int> _lastActionEventMs = {};
|
||||
|
||||
/// Generate a random display name for this session
|
||||
static String _generateDisplayName() {
|
||||
const adjectives = ['Happy', 'Sleepy', 'Sunny', 'Cozy', 'Chill', 'Swift', 'Brave', 'Calm', 'Jolly', 'Lucky'];
|
||||
@@ -180,6 +183,8 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
/// Create a new watch together session as host
|
||||
Future<String> createSession({
|
||||
required ControlMode controlMode,
|
||||
String? displayName,
|
||||
String? sessionId,
|
||||
String? mediaRatingKey,
|
||||
String? mediaServerId,
|
||||
String? mediaTitle,
|
||||
@@ -195,10 +200,10 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
_setupPeerServiceListeners();
|
||||
|
||||
try {
|
||||
final sessionId = await _peerService!.createSession();
|
||||
final createdSessionId = await _peerService!.createSession(sessionId: sessionId);
|
||||
|
||||
_session = WatchSession.createAsHost(
|
||||
sessionId: sessionId,
|
||||
sessionId: createdSessionId,
|
||||
hostPeerId: _peerService!.myPeerId!,
|
||||
controlMode: controlMode,
|
||||
mediaRatingKey: mediaRatingKey,
|
||||
@@ -206,8 +211,7 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
mediaTitle: mediaTitle,
|
||||
).copyWith(state: SessionState.connected);
|
||||
|
||||
// Generate a random display name and add self to participants
|
||||
_displayName = _generateDisplayName();
|
||||
_displayName = displayName ?? _generateDisplayName();
|
||||
_participants.add(Participant(peerId: _peerService!.myPeerId!, displayName: _displayName, isHost: true));
|
||||
|
||||
_syncManager = WatchTogetherSyncManager(
|
||||
@@ -219,9 +223,9 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
_wireSyncStateChanges();
|
||||
|
||||
notifyListeners();
|
||||
appLogger.d('WatchTogether: Session created: $sessionId');
|
||||
appLogger.d('WatchTogether: Session created: $createdSessionId');
|
||||
|
||||
return sessionId;
|
||||
return createdSessionId;
|
||||
} catch (e) {
|
||||
appLogger.e('WatchTogether: Failed to create session', error: e);
|
||||
_session = _session?.copyWith(state: SessionState.error, errorMessage: e.toString());
|
||||
@@ -231,7 +235,7 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Join an existing session as guest
|
||||
Future<void> joinSession(String sessionId) async {
|
||||
Future<void> joinSession(String sessionId, {String? displayName}) async {
|
||||
// Clean up any existing session
|
||||
await leaveSession();
|
||||
_lastHandledCurrentPlaybackKey = null;
|
||||
@@ -251,8 +255,7 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
// Session will be fully configured when we receive sessionConfig from host
|
||||
_session = _session!.copyWith(state: SessionState.connected, hostPeerId: 'wt-${sessionId.toUpperCase()}');
|
||||
|
||||
// Generate a random display name for this session
|
||||
_displayName = _generateDisplayName();
|
||||
_displayName = displayName ?? _generateDisplayName();
|
||||
|
||||
_syncManager = WatchTogetherSyncManager(
|
||||
peerService: _peerService!,
|
||||
@@ -285,6 +288,32 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enter a room by code — joins if it exists, creates if empty.
|
||||
///
|
||||
/// Returns `true` if the user became the host.
|
||||
Future<bool> enterRoom(String sessionId, {ControlMode controlMode = ControlMode.anyone, String? displayName}) async {
|
||||
// Probe the relay to determine if the room exists, then delegate to
|
||||
// the existing createSession / joinSession which handle all setup.
|
||||
final customRelayUrl = SettingsService.instanceOrNull?.getCustomRelayUrl();
|
||||
final probe = WatchTogetherPeerService(customBaseUrl: customRelayUrl);
|
||||
try {
|
||||
final becameHost = await probe.joinOrCreateSession(sessionId);
|
||||
await probe.disconnect();
|
||||
probe.dispose();
|
||||
|
||||
if (becameHost) {
|
||||
await createSession(controlMode: controlMode, displayName: displayName, sessionId: sessionId);
|
||||
} else {
|
||||
await joinSession(sessionId, displayName: displayName);
|
||||
}
|
||||
return becameHost;
|
||||
} catch (e) {
|
||||
await probe.disconnect();
|
||||
probe.dispose();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Leave the current session
|
||||
Future<void> leaveSession() async {
|
||||
if (_session == null) return;
|
||||
@@ -320,6 +349,7 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
_participants.clear();
|
||||
_isSyncing = false;
|
||||
_lastHandledCurrentPlaybackKey = null;
|
||||
_lastActionEventMs.clear();
|
||||
|
||||
notifyListeners();
|
||||
appLogger.d('WatchTogether: Session left');
|
||||
@@ -493,11 +523,39 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
// Handled at sync manager level (host responds with config)
|
||||
break;
|
||||
|
||||
case SyncMessageType.play:
|
||||
_emitActionEvent(message.peerId, ParticipantEventType.resumed);
|
||||
break;
|
||||
|
||||
case SyncMessageType.pause:
|
||||
_emitActionEvent(message.peerId, ParticipantEventType.paused);
|
||||
break;
|
||||
|
||||
case SyncMessageType.seek:
|
||||
_emitActionEvent(message.peerId, ParticipantEventType.seeked);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an action event for a remote peer (with 1s debounce per peer+type)
|
||||
void _emitActionEvent(String? peerId, ParticipantEventType type) {
|
||||
if (peerId == null || peerId == _peerService?.myPeerId) return;
|
||||
|
||||
final key = '$peerId:${type.name}';
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
final last = _lastActionEventMs[key] ?? 0;
|
||||
if (now - last < 1000) return;
|
||||
_lastActionEventMs[key] = now;
|
||||
|
||||
final name = _participants.where((p) => p.peerId == peerId).map((p) => p.displayName).firstOrNull;
|
||||
if (name != null) {
|
||||
_participantEventController.add(ParticipantEvent(displayName: name, type: type));
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle session config from host (guest only)
|
||||
/// This is handled at provider level so it's processed even before player is attached
|
||||
void _handleSessionConfig(SyncMessage message) {
|
||||
@@ -679,7 +737,7 @@ class WatchTogetherProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Type of participant event
|
||||
enum ParticipantEventType { joined, left }
|
||||
enum ParticipantEventType { joined, left, paused, resumed, seeked }
|
||||
|
||||
/// Event emitted when a participant joins or leaves
|
||||
class ParticipantEvent {
|
||||
|
||||
@@ -11,12 +11,14 @@ import '../../focus/focusable_button.dart';
|
||||
import '../../focus/focusable_wrapper.dart';
|
||||
import '../../services/settings_service.dart';
|
||||
import '../../utils/app_logger.dart';
|
||||
import '../../utils/provider_extensions.dart';
|
||||
import '../../utils/dialogs.dart';
|
||||
import '../../utils/snackbar_helper.dart';
|
||||
import '../../utils/video_player_navigation.dart';
|
||||
import '../../widgets/focused_scroll_scaffold.dart';
|
||||
import '../models/watch_session.dart';
|
||||
import '../providers/watch_together_provider.dart';
|
||||
import '../services/recent_rooms_service.dart';
|
||||
import '../services/watch_together_peer_service.dart';
|
||||
import '../widgets/join_session_dialog.dart';
|
||||
|
||||
@@ -80,16 +82,23 @@ class _NotInSessionView extends StatefulWidget {
|
||||
class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
bool _isCreating = false;
|
||||
bool _isJoining = false;
|
||||
String? _enteringRoomCode;
|
||||
bool? _healthOk;
|
||||
String? _customRelayUrl;
|
||||
List<RecentRoom> _recentRooms = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_customRelayUrl = SettingsService.instanceOrNull?.getCustomRelayUrl();
|
||||
_recentRooms = RecentRoomsService.getRecentRooms();
|
||||
_checkHealth();
|
||||
}
|
||||
|
||||
bool get _isBusy => _isCreating || _isJoining || _enteringRoomCode != null;
|
||||
|
||||
String? get _plexDisplayName => context.userProfile.currentUser?.displayName;
|
||||
|
||||
Future<void> _checkHealth() async {
|
||||
try {
|
||||
final client = HttpClient();
|
||||
@@ -117,7 +126,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Symbols.group_rounded, size: 80, color: theme.colorScheme.primary),
|
||||
const SizedBox(height: 24),
|
||||
@@ -153,10 +162,10 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: FocusableButton(
|
||||
autofocus: true,
|
||||
onPressed: _isCreating || _isJoining ? null : _createSession,
|
||||
autofocus: _recentRooms.isEmpty,
|
||||
onPressed: _isBusy ? null : _createSession,
|
||||
child: FilledButton.icon(
|
||||
onPressed: _isCreating || _isJoining ? null : _createSession,
|
||||
onPressed: _isBusy ? null : _createSession,
|
||||
icon: _isCreating
|
||||
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Symbols.add_rounded),
|
||||
@@ -168,9 +177,9 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: FocusableButton(
|
||||
onPressed: _isCreating || _isJoining ? null : _joinSession,
|
||||
onPressed: _isBusy ? null : _joinSession,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: _isCreating || _isJoining ? null : _joinSession,
|
||||
onPressed: _isBusy ? null : _joinSession,
|
||||
icon: _isJoining
|
||||
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Symbols.group_add_rounded),
|
||||
@@ -178,6 +187,22 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_recentRooms.isNotEmpty) ...[
|
||||
const SizedBox(height: 32),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(t.watchTogether.recentRooms, style: theme.textTheme.titleSmall),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
..._recentRooms.map((room) => _RecentRoomTile(
|
||||
room: room,
|
||||
isBusy: _isBusy,
|
||||
isEntering: _enteringRoomCode == room.code,
|
||||
onTap: () => _enterRoom(room),
|
||||
onRename: () => _renameRoom(room),
|
||||
onRemove: () => _removeRoom(room),
|
||||
)),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -192,7 +217,12 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
setState(() => _isCreating = true);
|
||||
|
||||
try {
|
||||
await widget.watchTogether.createSession(controlMode: controlMode);
|
||||
final sessionId = await widget.watchTogether.createSession(
|
||||
controlMode: controlMode,
|
||||
displayName: _plexDisplayName,
|
||||
);
|
||||
await RecentRoomsService.addOrUpdateRoom(sessionId);
|
||||
if (mounted) setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
|
||||
} catch (e) {
|
||||
appLogger.e('Failed to create session', error: e);
|
||||
if (mounted) {
|
||||
@@ -250,7 +280,9 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
setState(() => _isJoining = true);
|
||||
|
||||
try {
|
||||
await widget.watchTogether.joinSession(sessionId);
|
||||
await widget.watchTogether.joinSession(sessionId, displayName: _plexDisplayName);
|
||||
await RecentRoomsService.addOrUpdateRoom(sessionId);
|
||||
if (mounted) setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
|
||||
} catch (e) {
|
||||
appLogger.e('Failed to join session', error: e);
|
||||
if (mounted) {
|
||||
@@ -262,6 +294,133 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _enterRoom(RecentRoom room) async {
|
||||
setState(() => _enteringRoomCode = room.code);
|
||||
|
||||
try {
|
||||
await widget.watchTogether.enterRoom(room.code, displayName: _plexDisplayName);
|
||||
await RecentRoomsService.addOrUpdateRoom(room.code);
|
||||
if (mounted) setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
|
||||
} catch (e) {
|
||||
appLogger.e('Failed to enter room', error: e);
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${t.watchTogether.failedToJoin}: $e')));
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _enteringRoomCode = null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _renameRoom(RecentRoom room) async {
|
||||
final controller = TextEditingController(text: room.name ?? '');
|
||||
final name = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(t.watchTogether.renameRoom),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(hintText: room.code),
|
||||
onSubmitted: (value) => Navigator.pop(context, value),
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context), child: Text(t.common.cancel)),
|
||||
FilledButton(onPressed: () => Navigator.pop(context, controller.text), child: Text(t.common.save)),
|
||||
],
|
||||
),
|
||||
);
|
||||
controller.dispose();
|
||||
if (name == null || !mounted) return;
|
||||
|
||||
await RecentRoomsService.renameRoom(room.code, name.isEmpty ? null : name);
|
||||
setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
|
||||
}
|
||||
|
||||
Future<void> _removeRoom(RecentRoom room) async {
|
||||
await RecentRoomsService.removeRoom(room.code);
|
||||
setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
|
||||
}
|
||||
}
|
||||
|
||||
class _RecentRoomTile extends StatelessWidget {
|
||||
final RecentRoom room;
|
||||
final bool isBusy;
|
||||
final bool isEntering;
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback onRename;
|
||||
final VoidCallback onRemove;
|
||||
|
||||
const _RecentRoomTile({
|
||||
required this.room,
|
||||
required this.isBusy,
|
||||
required this.isEntering,
|
||||
required this.onTap,
|
||||
required this.onRename,
|
||||
required this.onRemove,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final title = room.name ?? room.code;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: FocusableWrapper(
|
||||
useBackgroundFocus: true,
|
||||
borderRadius: 12,
|
||||
onSelect: isBusy ? null : onTap,
|
||||
onLongPress: () => _showActions(context),
|
||||
child: ListTile(
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
|
||||
leading: isEntering
|
||||
? const SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Symbols.meeting_room_rounded),
|
||||
title: Text(title, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
subtitle: room.name != null
|
||||
? Text(room.code, style: TextStyle(fontFamily: 'monospace', color: theme.colorScheme.onSurfaceVariant))
|
||||
: null,
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Symbols.more_vert_rounded),
|
||||
onPressed: () => _showActions(context),
|
||||
),
|
||||
onTap: isBusy ? null : onTap,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showActions(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.edit_rounded),
|
||||
title: Text(t.watchTogether.renameRoom),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
onRename();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Symbols.delete_rounded, color: Theme.of(context).colorScheme.error),
|
||||
title: Text(t.watchTogether.removeRoom, style: TextStyle(color: Theme.of(context).colorScheme.error)),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
onRemove();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Content shown when in an active session (without scroll wrapper)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../services/settings_service.dart';
|
||||
|
||||
class RecentRoom {
|
||||
final String code;
|
||||
final String? name;
|
||||
final DateTime lastUsed;
|
||||
|
||||
const RecentRoom({required this.code, this.name, required this.lastUsed});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'code': code,
|
||||
if (name != null) 'name': name,
|
||||
'lastUsed': lastUsed.millisecondsSinceEpoch,
|
||||
};
|
||||
|
||||
factory RecentRoom.fromJson(Map<String, dynamic> json) => RecentRoom(
|
||||
code: json['code'] as String,
|
||||
name: json['name'] as String?,
|
||||
lastUsed: DateTime.fromMillisecondsSinceEpoch(json['lastUsed'] as int),
|
||||
);
|
||||
|
||||
RecentRoom copyWith({String? code, String? name, DateTime? lastUsed, bool clearName = false}) => RecentRoom(
|
||||
code: code ?? this.code,
|
||||
name: clearName ? null : (name ?? this.name),
|
||||
lastUsed: lastUsed ?? this.lastUsed,
|
||||
);
|
||||
}
|
||||
|
||||
class RecentRoomsService {
|
||||
static const int _maxRooms = 20;
|
||||
|
||||
static List<RecentRoom> getRecentRooms() {
|
||||
final json = SettingsService.instanceOrNull?.getRecentRooms();
|
||||
if (json == null) return [];
|
||||
try {
|
||||
final list = jsonDecode(json) as List<dynamic>;
|
||||
final rooms = list.map((e) => RecentRoom.fromJson(e as Map<String, dynamic>)).toList();
|
||||
rooms.sort((a, b) => b.lastUsed.compareTo(a.lastUsed));
|
||||
return rooms;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _save(List<RecentRoom> rooms) async {
|
||||
rooms.sort((a, b) => b.lastUsed.compareTo(a.lastUsed));
|
||||
if (rooms.length > _maxRooms) rooms.removeRange(_maxRooms, rooms.length);
|
||||
await SettingsService.instanceOrNull?.setRecentRooms(jsonEncode(rooms.map((r) => r.toJson()).toList()));
|
||||
}
|
||||
|
||||
static Future<void> addOrUpdateRoom(String code, {String? name}) async {
|
||||
final rooms = getRecentRooms();
|
||||
final index = rooms.indexWhere((r) => r.code == code);
|
||||
if (index >= 0) {
|
||||
rooms[index] = rooms[index].copyWith(lastUsed: DateTime.now(), name: name ?? rooms[index].name);
|
||||
} else {
|
||||
rooms.add(RecentRoom(code: code, name: name, lastUsed: DateTime.now()));
|
||||
}
|
||||
await _save(rooms);
|
||||
}
|
||||
|
||||
static Future<void> removeRoom(String code) async {
|
||||
final rooms = getRecentRooms();
|
||||
rooms.removeWhere((r) => r.code == code);
|
||||
await _save(rooms);
|
||||
}
|
||||
|
||||
static Future<void> renameRoom(String code, String? name) async {
|
||||
final rooms = getRecentRooms();
|
||||
final index = rooms.indexWhere((r) => r.code == code);
|
||||
if (index >= 0) {
|
||||
rooms[index] = rooms[index].copyWith(name: name, clearName: name == null);
|
||||
await _save(rooms);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:uuid/uuid.dart';
|
||||
import '../../utils/future_extensions.dart';
|
||||
@@ -98,9 +99,11 @@ class WatchTogetherPeerService with KeepaliveMixin {
|
||||
/// List of connected peer IDs
|
||||
List<String> get connectedPeers => _connectedPeers.toList();
|
||||
|
||||
/// Generate a short, readable session ID
|
||||
String _generateSessionId() {
|
||||
return const Uuid().v4().substring(0, 8).toUpperCase();
|
||||
/// Generate a short, readable session ID (5 alphanumeric chars)
|
||||
static String _generateSessionId() {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
final random = Random.secure();
|
||||
return String.fromCharCodes(List.generate(5, (_) => chars.codeUnitAt(random.nextInt(chars.length))));
|
||||
}
|
||||
|
||||
/// Connect to the relay WebSocket and set up the message listener.
|
||||
@@ -308,13 +311,14 @@ class WatchTogetherPeerService with KeepaliveMixin {
|
||||
/// Create a new session as host
|
||||
///
|
||||
/// Returns the session ID that others can use to join.
|
||||
Future<String> createSession() async {
|
||||
/// If [sessionId] is provided, uses that instead of generating a new one.
|
||||
Future<String> createSession({String? sessionId}) async {
|
||||
if (_channel != null) {
|
||||
await disconnect();
|
||||
}
|
||||
|
||||
_isHost = true;
|
||||
_sessionId = _generateSessionId();
|
||||
_sessionId = sessionId?.toUpperCase() ?? _generateSessionId();
|
||||
_myPeerId = 'wt-$_sessionId';
|
||||
_reconnectAttempts = 0;
|
||||
|
||||
@@ -380,6 +384,20 @@ class WatchTogetherPeerService with KeepaliveMixin {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to join a session; if it doesn't exist, create it as host.
|
||||
///
|
||||
/// Returns `true` if the user became the host (room was empty).
|
||||
Future<bool> joinOrCreateSession(String sessionId) async {
|
||||
try {
|
||||
await joinSession(sessionId);
|
||||
return false; // joined as guest
|
||||
} on PeerError catch (e) {
|
||||
if (e.type != PeerErrorType.serverError) rethrow;
|
||||
await createSession(sessionId: sessionId);
|
||||
return true; // created as host
|
||||
}
|
||||
}
|
||||
|
||||
/// Broadcast a message to all connected peers
|
||||
void broadcast(SyncMessage message) {
|
||||
final payload = message.toJson();
|
||||
|
||||
@@ -72,7 +72,7 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
textCapitalization: TextCapitalization.characters,
|
||||
maxLength: 8,
|
||||
maxLength: 5,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9]')),
|
||||
UpperCaseTextFormatter(),
|
||||
@@ -81,8 +81,8 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
|
||||
if (value == null || value.isEmpty) {
|
||||
return t.watchTogether.pleaseEnterCode;
|
||||
}
|
||||
if (value.length != 8) {
|
||||
return t.watchTogether.codeMustBe8Chars;
|
||||
if (value.length != 5) {
|
||||
return t.watchTogether.codeMustBe5Chars;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -123,7 +123,7 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
|
||||
// Clean the pasted text - extract alphanumeric characters and take first 8
|
||||
final cleaned = data!.text!.replaceAll(RegExp(r'[^A-Za-z0-9]'), '').toUpperCase();
|
||||
if (cleaned.isNotEmpty) {
|
||||
_sessionIdController.text = cleaned.substring(0, cleaned.length.clamp(0, 8));
|
||||
_sessionIdController.text = cleaned.substring(0, cleaned.length.clamp(0, 5));
|
||||
_sessionIdController.selection = TextSelection.collapsed(offset: _sessionIdController.text.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,9 +346,13 @@ class _ParticipantNotificationOverlayState extends State<ParticipantNotification
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _notifications.map((n) {
|
||||
final text = n.event.type == ParticipantEventType.joined
|
||||
? t.watchTogether.participantJoined(name: n.event.displayName)
|
||||
: t.watchTogether.participantLeft(name: n.event.displayName);
|
||||
final text = switch (n.event.type) {
|
||||
ParticipantEventType.joined => t.watchTogether.participantJoined(name: n.event.displayName),
|
||||
ParticipantEventType.left => t.watchTogether.participantLeft(name: n.event.displayName),
|
||||
ParticipantEventType.paused => t.watchTogether.participantPaused(name: n.event.displayName),
|
||||
ParticipantEventType.resumed => t.watchTogether.participantResumed(name: n.event.displayName),
|
||||
ParticipantEventType.seeked => t.watchTogether.participantSeeked(name: n.event.displayName),
|
||||
};
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
|
||||
Reference in New Issue
Block a user