fix: watch together translations

This commit is contained in:
edde746
2025-12-19 03:29:56 +01:00
parent 289ca393c7
commit b1d2b4f3f1
11 changed files with 1616 additions and 66 deletions
+1229 -2
View File
File diff suppressed because it is too large Load Diff
+52
View File
@@ -481,6 +481,58 @@
"errorReordering": "Failed to reorder playlist item",
"errorRemoving": "Failed to remove from playlist"
},
"watchTogether": {
"title": "Watch Together",
"description": "Watch content in sync with friends and family",
"createSession": "Create Session",
"creating": "Creating...",
"joinSession": "Join Session",
"joining": "Joining...",
"controlMode": "Control Mode",
"controlModeQuestion": "Who can control playback?",
"hostOnly": "Host Only",
"anyone": "Anyone",
"hostingSession": "Hosting Session",
"inSession": "In Session",
"sessionCode": "Session Code",
"hostControlsPlayback": "Host controls playback",
"anyoneCanControl": "Anyone can control playback",
"hostControls": "Host controls",
"anyoneControls": "Anyone controls",
"participants": "Participants",
"host": "Host",
"hostBadge": "HOST",
"youAreHost": "You are the host",
"watchingWithOthers": "Watching with others",
"endSession": "End Session",
"leaveSession": "Leave Session",
"endSessionQuestion": "End Session?",
"leaveSessionQuestion": "Leave Session?",
"endSessionConfirm": "This will end the session for all participants.",
"leaveSessionConfirm": "You will be removed from the session.",
"endSessionConfirmOverlay": "This will end the watch session for all participants.",
"leaveSessionConfirmOverlay": "You will be disconnected from the watch session.",
"end": "End",
"leave": "Leave",
"inviteOthers": "Invite others",
"syncing": "Syncing...",
"participant": "participant",
"participantsPlural": "participants",
"copyCode": "Copy code",
"shareInstructions": "Share this code with others to let them join your watch session.",
"codeCopied": "Session code copied to clipboard",
"share": "Share",
"inviteText": "Join my Watch Together session!\n\nSession Code: ${sessionId}",
"inviteSubject": "Watch Together Invite",
"joinWatchSession": "Join Watch Session",
"enterCodeHint": "Enter 8-character code",
"pasteFromClipboard": "Paste from clipboard",
"pleaseEnterCode": "Please enter a session code",
"codeMustBe8Chars": "Session code must be 8 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"
},
"downloads": {
"title": "Downloads",
"manage": "Manage",
+52
View File
@@ -498,5 +498,57 @@
"removedFromCollection": "Aus Sammlung entfernt",
"removeFromCollectionFailed": "Entfernen aus Sammlung fehlgeschlagen",
"removeFromCollectionError": "Fehler beim Entfernen aus der Sammlung: ${error}"
},
"watchTogether": {
"title": "Gemeinsam Schauen",
"description": "Inhalte synchron mit Freunden und Familie schauen",
"createSession": "Sitzung Erstellen",
"creating": "Erstellen...",
"joinSession": "Sitzung Beitreten",
"joining": "Beitreten...",
"controlMode": "Steuerungsmodus",
"controlModeQuestion": "Wer kann die Wiedergabe steuern?",
"hostOnly": "Nur Host",
"anyone": "Alle",
"hostingSession": "Sitzung Hosten",
"inSession": "In Sitzung",
"sessionCode": "Sitzungscode",
"hostControlsPlayback": "Host steuert die Wiedergabe",
"anyoneCanControl": "Alle können die Wiedergabe steuern",
"hostControls": "Host steuert",
"anyoneControls": "Alle steuern",
"participants": "Teilnehmer",
"host": "Host",
"hostBadge": "HOST",
"youAreHost": "Du bist der Host",
"watchingWithOthers": "Mit anderen schauen",
"endSession": "Sitzung Beenden",
"leaveSession": "Sitzung Verlassen",
"endSessionQuestion": "Sitzung Beenden?",
"leaveSessionQuestion": "Sitzung Verlassen?",
"endSessionConfirm": "Dies beendet die Sitzung für alle Teilnehmer.",
"leaveSessionConfirm": "Du wirst aus der Sitzung entfernt.",
"endSessionConfirmOverlay": "Dies beendet die Schausitzung für alle Teilnehmer.",
"leaveSessionConfirmOverlay": "Du wirst von der Schausitzung getrennt.",
"end": "Beenden",
"leave": "Verlassen",
"inviteOthers": "Andere einladen",
"syncing": "Synchronisieren...",
"participant": "Teilnehmer",
"participantsPlural": "Teilnehmer",
"copyCode": "Code kopieren",
"shareInstructions": "Teile diesen Code mit anderen, damit sie deiner Schausitzung beitreten können.",
"codeCopied": "Sitzungscode in Zwischenablage kopiert",
"share": "Teilen",
"inviteText": "Tritt meiner Gemeinsam Schauen-Sitzung bei!\n\nSitzungscode: ${sessionId}",
"inviteSubject": "Gemeinsam Schauen Einladung",
"joinWatchSession": "Schausitzung Beitreten",
"enterCodeHint": "8-stelligen Code eingeben",
"pasteFromClipboard": "Aus Zwischenablage einfügen",
"pleaseEnterCode": "Bitte gib einen Sitzungscode ein",
"codeMustBe8Chars": "Sitzungscode muss 8 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"
}
}
+52
View File
@@ -498,5 +498,57 @@
"removedFromCollection": "Rimosso dalla raccolta",
"removeFromCollectionFailed": "Impossibile rimuovere dalla raccolta",
"removeFromCollectionError": "Errore durante la rimozione dalla raccolta: ${error}"
},
"watchTogether": {
"title": "Guarda Insieme",
"description": "Guarda contenuti in sincronia con amici e familiari",
"createSession": "Crea Sessione",
"creating": "Creazione...",
"joinSession": "Unisciti alla Sessione",
"joining": "Connessione...",
"controlMode": "Modalità di Controllo",
"controlModeQuestion": "Chi può controllare la riproduzione?",
"hostOnly": "Solo Host",
"anyone": "Tutti",
"hostingSession": "Hosting Sessione",
"inSession": "In Sessione",
"sessionCode": "Codice Sessione",
"hostControlsPlayback": "L'host controlla la riproduzione",
"anyoneCanControl": "Tutti possono controllare la riproduzione",
"hostControls": "Controllo host",
"anyoneControls": "Controllo di tutti",
"participants": "Partecipanti",
"host": "Host",
"hostBadge": "HOST",
"youAreHost": "Sei l'host",
"watchingWithOthers": "Guardando con altri",
"endSession": "Termina Sessione",
"leaveSession": "Lascia Sessione",
"endSessionQuestion": "Terminare la Sessione?",
"leaveSessionQuestion": "Lasciare la Sessione?",
"endSessionConfirm": "Questo terminerà la sessione per tutti i partecipanti.",
"leaveSessionConfirm": "Sarai rimosso dalla sessione.",
"endSessionConfirmOverlay": "Questo terminerà la sessione di visione per tutti i partecipanti.",
"leaveSessionConfirmOverlay": "Sarai disconnesso dalla sessione di visione.",
"end": "Termina",
"leave": "Lascia",
"inviteOthers": "Invita altri",
"syncing": "Sincronizzazione...",
"participant": "partecipante",
"participantsPlural": "partecipanti",
"copyCode": "Copia codice",
"shareInstructions": "Condividi questo codice con altri per farli unire alla tua sessione di visione.",
"codeCopied": "Codice sessione copiato negli appunti",
"share": "Condividi",
"inviteText": "Unisciti alla mia sessione Guarda Insieme!\n\nCodice Sessione: ${sessionId}",
"inviteSubject": "Invito Guarda Insieme",
"joinWatchSession": "Unisciti alla Sessione di Visione",
"enterCodeHint": "Inserisci codice di 8 caratteri",
"pasteFromClipboard": "Incolla dagli appunti",
"pleaseEnterCode": "Inserisci un codice sessione",
"codeMustBe8Chars": "Il codice sessione deve essere di 8 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"
}
}
+52
View File
@@ -498,5 +498,57 @@
"removedFromCollection": "Uit collectie verwijderd",
"removeFromCollectionFailed": "Verwijderen uit collectie mislukt",
"removeFromCollectionError": "Fout bij verwijderen uit collectie: ${error}"
},
"watchTogether": {
"title": "Samen Kijken",
"description": "Kijk synchroon met vrienden en familie",
"createSession": "Sessie Maken",
"creating": "Maken...",
"joinSession": "Sessie Deelnemen",
"joining": "Deelnemen...",
"controlMode": "Controlemodus",
"controlModeQuestion": "Wie kan het afspelen bedienen?",
"hostOnly": "Alleen Host",
"anyone": "Iedereen",
"hostingSession": "Sessie Hosten",
"inSession": "In Sessie",
"sessionCode": "Sessiecode",
"hostControlsPlayback": "Host bedient het afspelen",
"anyoneCanControl": "Iedereen kan het afspelen bedienen",
"hostControls": "Host bedient",
"anyoneControls": "Iedereen bedient",
"participants": "Deelnemers",
"host": "Host",
"hostBadge": "HOST",
"youAreHost": "Jij bent de host",
"watchingWithOthers": "Kijken met anderen",
"endSession": "Sessie Beëindigen",
"leaveSession": "Sessie Verlaten",
"endSessionQuestion": "Sessie Beëindigen?",
"leaveSessionQuestion": "Sessie Verlaten?",
"endSessionConfirm": "Dit beëindigt de sessie voor alle deelnemers.",
"leaveSessionConfirm": "Je wordt uit de sessie verwijderd.",
"endSessionConfirmOverlay": "Dit beëindigt de kijksessie voor alle deelnemers.",
"leaveSessionConfirmOverlay": "Je wordt losgekoppeld van de kijksessie.",
"end": "Beëindigen",
"leave": "Verlaten",
"inviteOthers": "Anderen uitnodigen",
"syncing": "Synchroniseren...",
"participant": "deelnemer",
"participantsPlural": "deelnemers",
"copyCode": "Code kopiëren",
"shareInstructions": "Deel deze code met anderen om hen te laten deelnemen aan je kijksessie.",
"codeCopied": "Sessiecode gekopieerd naar klembord",
"share": "Delen",
"inviteText": "Doe mee met mijn Samen Kijken sessie!\n\nSessiecode: ${sessionId}",
"inviteSubject": "Samen Kijken Uitnodiging",
"joinWatchSession": "Kijksessie Deelnemen",
"enterCodeHint": "Voer 8-teken code in",
"pasteFromClipboard": "Plakken van klembord",
"pleaseEnterCode": "Voer een sessiecode in",
"codeMustBe8Chars": "Sessiecode moet 8 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"
}
}
+52
View File
@@ -498,5 +498,57 @@
"removedFromCollection": "Borttagen från samling",
"removeFromCollectionFailed": "Misslyckades med att ta bort från samling",
"removeFromCollectionError": "Fel vid borttagning från samling: ${error}"
},
"watchTogether": {
"title": "Titta Tillsammans",
"description": "Titta på innehåll synkroniserat med vänner och familj",
"createSession": "Skapa Session",
"creating": "Skapar...",
"joinSession": "Gå med i Session",
"joining": "Ansluter...",
"controlMode": "Kontrollläge",
"controlModeQuestion": "Vem kan styra uppspelningen?",
"hostOnly": "Endast Värd",
"anyone": "Alla",
"hostingSession": "Värd för Session",
"inSession": "I Session",
"sessionCode": "Sessionskod",
"hostControlsPlayback": "Värden styr uppspelningen",
"anyoneCanControl": "Alla kan styra uppspelningen",
"hostControls": "Värd styr",
"anyoneControls": "Alla styr",
"participants": "Deltagare",
"host": "Värd",
"hostBadge": "VÄRD",
"youAreHost": "Du är värden",
"watchingWithOthers": "Tittar med andra",
"endSession": "Avsluta Session",
"leaveSession": "Lämna Session",
"endSessionQuestion": "Avsluta Session?",
"leaveSessionQuestion": "Lämna Session?",
"endSessionConfirm": "Detta avslutar sessionen för alla deltagare.",
"leaveSessionConfirm": "Du kommer att tas bort från sessionen.",
"endSessionConfirmOverlay": "Detta avslutar tittarsessionen för alla deltagare.",
"leaveSessionConfirmOverlay": "Du kommer att kopplas bort från tittarsessionen.",
"end": "Avsluta",
"leave": "Lämna",
"inviteOthers": "Bjud in andra",
"syncing": "Synkroniserar...",
"participant": "deltagare",
"participantsPlural": "deltagare",
"copyCode": "Kopiera kod",
"shareInstructions": "Dela denna kod med andra för att låta dem gå med i din tittarsession.",
"codeCopied": "Sessionskod kopierad till urklipp",
"share": "Dela",
"inviteText": "Gå med i min Titta Tillsammans-session!\n\nSessionskod: ${sessionId}",
"inviteSubject": "Titta Tillsammans-inbjudan",
"joinWatchSession": "Gå med i Tittarsession",
"enterCodeHint": "Ange 8-teckens kod",
"pasteFromClipboard": "Klistra in från urklipp",
"pleaseEnterCode": "Vänligen ange en sessionskod",
"codeMustBe8Chars": "Sessionskod måste vara 8 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"
}
}
+52
View File
@@ -498,5 +498,57 @@
"removedFromCollection": "已从合集移除",
"removeFromCollectionFailed": "从合集移除失败",
"removeFromCollectionError": "从合集移除时出错:${error}"
},
"watchTogether": {
"title": "一起看",
"description": "与朋友和家人同步观看内容",
"createSession": "创建会话",
"creating": "创建中...",
"joinSession": "加入会话",
"joining": "加入中...",
"controlMode": "控制模式",
"controlModeQuestion": "谁可以控制播放?",
"hostOnly": "仅主持人",
"anyone": "任何人",
"hostingSession": "主持会话",
"inSession": "在会话中",
"sessionCode": "会话代码",
"hostControlsPlayback": "主持人控制播放",
"anyoneCanControl": "任何人都可以控制播放",
"hostControls": "主持人控制",
"anyoneControls": "任何人控制",
"participants": "参与者",
"host": "主持人",
"hostBadge": "主持人",
"youAreHost": "你是主持人",
"watchingWithOthers": "与他人一起观看",
"endSession": "结束会话",
"leaveSession": "离开会话",
"endSessionQuestion": "结束会话?",
"leaveSessionQuestion": "离开会话?",
"endSessionConfirm": "这将为所有参与者结束会话。",
"leaveSessionConfirm": "你将被移出会话。",
"endSessionConfirmOverlay": "这将为所有参与者结束观看会话。",
"leaveSessionConfirmOverlay": "你将断开与观看会话的连接。",
"end": "结束",
"leave": "离开",
"inviteOthers": "邀请他人",
"syncing": "同步中...",
"participant": "参与者",
"participantsPlural": "参与者",
"copyCode": "复制代码",
"shareInstructions": "与他人分享此代码以让他们加入你的观看会话。",
"codeCopied": "会话代码已复制到剪贴板",
"share": "分享",
"inviteText": "加入我的一起看会话!\n\n会话代码:${sessionId}",
"inviteSubject": "一起看邀请",
"joinWatchSession": "加入观看会话",
"enterCodeHint": "输入8位代码",
"pasteFromClipboard": "从剪贴板粘贴",
"pleaseEnterCode": "请输入会话代码",
"codeMustBe8Chars": "会话代码必须是8个字符",
"joinInstructions": "输入主持人分享的会话代码以加入他们的观看会话。",
"failedToCreate": "创建会话失败",
"failedToJoin": "加入会话失败"
}
}
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import '../../i18n/strings.g.dart';
import '../../utils/app_logger.dart';
import '../../widgets/focused_scroll_scaffold.dart';
import '../models/watch_session.dart';
@@ -27,7 +28,7 @@ class WatchTogetherScreen extends StatelessWidget {
return PopScope(
canPop: canGoBack,
child: FocusedScrollScaffold(
title: const Text('Watch Together'),
title: Text(t.watchTogether.title),
automaticallyImplyLeading: canGoBack,
slivers: watchTogether.isInSession
? _buildActiveSessionSlivers(watchTogether)
@@ -83,10 +84,10 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
children: [
Icon(Symbols.group_rounded, size: 80, color: theme.colorScheme.primary),
const SizedBox(height: 24),
Text('Watch Together', style: theme.textTheme.headlineMedium, textAlign: TextAlign.center),
Text(t.watchTogether.title, style: theme.textTheme.headlineMedium, textAlign: TextAlign.center),
const SizedBox(height: 8),
Text(
'Watch content in sync with friends and family',
t.watchTogether.description,
style: theme.textTheme.bodyLarge?.copyWith(color: theme.colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
@@ -98,7 +99,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
icon: _isCreating
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Icon(Symbols.add_rounded),
label: Text(_isCreating ? 'Creating...' : 'Create Session'),
label: Text(_isCreating ? t.watchTogether.creating : t.watchTogether.createSession),
),
),
const SizedBox(height: 16),
@@ -109,7 +110,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
icon: _isJoining
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Icon(Symbols.group_add_rounded),
label: Text(_isJoining ? 'Joining...' : 'Join Session'),
label: Text(_isJoining ? t.watchTogether.joining : t.watchTogether.joinSession),
),
),
],
@@ -130,7 +131,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
} catch (e) {
appLogger.e('Failed to create session', error: e);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Failed to create session: $e')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${t.watchTogether.failedToCreate}: $e')));
}
} finally {
if (mounted) {
@@ -143,12 +144,18 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
return showDialog<ControlMode>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Control Mode'),
content: const Text('Who can control playback?'),
title: Text(t.watchTogether.controlMode),
content: Text(t.watchTogether.controlModeQuestion),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Cancel')),
TextButton(onPressed: () => Navigator.pop(context, ControlMode.hostOnly), child: const Text('Host Only')),
FilledButton(onPressed: () => Navigator.pop(context, ControlMode.anyone), child: const Text('Anyone')),
TextButton(onPressed: () => Navigator.pop(context), child: Text(t.common.cancel)),
TextButton(
onPressed: () => Navigator.pop(context, ControlMode.hostOnly),
child: Text(t.watchTogether.hostOnly),
),
FilledButton(
onPressed: () => Navigator.pop(context, ControlMode.anyone),
child: Text(t.watchTogether.anyone),
),
],
),
);
@@ -165,7 +172,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
} catch (e) {
appLogger.e('Failed to join session', error: e);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Failed to join session: $e')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${t.watchTogether.failedToJoin}: $e')));
}
} finally {
if (mounted) {
@@ -208,11 +215,11 @@ class _ActiveSessionContent extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
watchTogether.isHost ? 'Hosting Session' : 'In Session',
watchTogether.isHost ? t.watchTogether.hostingSession : t.watchTogether.inSession,
style: theme.textTheme.titleMedium,
),
Text(
'Code: ${session.sessionId}',
'${t.watchTogether.sessionCode}: ${session.sessionId}',
style: theme.textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
color: theme.colorScheme.onSurfaceVariant,
@@ -238,8 +245,8 @@ class _ActiveSessionContent extends StatelessWidget {
const SizedBox(width: 8),
Text(
session.controlMode == ControlMode.anyone
? 'Anyone can control playback'
: 'Host controls playback',
? t.watchTogether.anyoneCanControl
: t.watchTogether.hostControlsPlayback,
style: theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.onSurfaceVariant),
),
],
@@ -262,7 +269,10 @@ class _ActiveSessionContent extends StatelessWidget {
children: [
Icon(Symbols.people_rounded, color: theme.colorScheme.primary),
const SizedBox(width: 12),
Text('Participants (${watchTogether.participantCount})', style: theme.textTheme.titleMedium),
Text(
'${t.watchTogether.participants} (${watchTogether.participantCount})',
style: theme.textTheme.titleMedium,
),
],
),
const SizedBox(height: 12),
@@ -287,7 +297,7 @@ class _ActiveSessionContent extends StatelessWidget {
borderRadius: BorderRadius.circular(12),
),
child: Text(
'Host',
t.watchTogether.host,
style: theme.textTheme.labelSmall?.copyWith(color: Colors.amber.shade700),
),
),
@@ -321,7 +331,7 @@ class _ActiveSessionContent extends StatelessWidget {
side: BorderSide(color: theme.colorScheme.error),
),
icon: Icon(watchTogether.isHost ? Symbols.close_rounded : Symbols.logout_rounded),
label: Text(watchTogether.isHost ? 'End Session' : 'Leave Session'),
label: Text(watchTogether.isHost ? t.watchTogether.endSession : t.watchTogether.leaveSession),
),
),
],
@@ -332,18 +342,14 @@ class _ActiveSessionContent extends StatelessWidget {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(watchTogether.isHost ? 'End Session?' : 'Leave Session?'),
content: Text(
watchTogether.isHost
? 'This will end the session for all participants.'
: 'You will be removed from the session.',
),
title: Text(watchTogether.isHost ? t.watchTogether.endSessionQuestion : t.watchTogether.leaveSessionQuestion),
content: Text(watchTogether.isHost ? t.watchTogether.endSessionConfirm : t.watchTogether.leaveSessionConfirm),
actions: [
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')),
TextButton(onPressed: () => Navigator.pop(context, false), child: Text(t.common.cancel)),
FilledButton(
onPressed: () => Navigator.pop(context, true),
style: FilledButton.styleFrom(backgroundColor: Theme.of(context).colorScheme.error),
child: Text(watchTogether.isHost ? 'End' : 'Leave'),
child: Text(watchTogether.isHost ? t.watchTogether.end : t.watchTogether.leave),
),
],
),
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../../i18n/strings.g.dart';
/// Dialog for joining a watch together session
class JoinSessionDialog extends StatefulWidget {
const JoinSessionDialog({super.key});
@@ -40,7 +42,7 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
children: [
Icon(Symbols.group_add, color: theme.colorScheme.primary),
const SizedBox(width: 12),
Expanded(child: Text('Join Watch Session', style: theme.textTheme.titleLarge)),
Expanded(child: Text(t.watchTogether.joinWatchSession, style: theme.textTheme.titleLarge)),
IconButton(onPressed: () => Navigator.of(context).pop(), icon: const Icon(Symbols.close)),
],
),
@@ -51,13 +53,13 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
TextFormField(
controller: _sessionIdController,
decoration: InputDecoration(
labelText: 'Session Code',
hintText: 'Enter 8-character code',
labelText: t.watchTogether.sessionCode,
hintText: t.watchTogether.enterCodeHint,
prefixIcon: const Icon(Symbols.tag),
suffixIcon: IconButton(
onPressed: _pasteFromClipboard,
icon: const Icon(Symbols.content_paste),
tooltip: 'Paste from clipboard',
tooltip: t.watchTogether.pasteFromClipboard,
),
border: const OutlineInputBorder(),
),
@@ -69,10 +71,10 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a session code';
return t.watchTogether.pleaseEnterCode;
}
if (value.length != 8) {
return 'Session code must be 8 characters';
return t.watchTogether.codeMustBe8Chars;
}
return null;
},
@@ -84,7 +86,7 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
// Instructions
Text(
'Enter the session code shared by the host to join their watch session.',
t.watchTogether.joinInstructions,
style: theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.onSurfaceVariant),
),
@@ -94,7 +96,7 @@ class _JoinSessionDialogState extends State<JoinSessionDialog> {
FilledButton.icon(
onPressed: _join,
icon: const Icon(Symbols.group_add),
label: const Text('Join Session'),
label: Text(t.watchTogether.joinSession),
),
],
),
@@ -4,6 +4,8 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:share_plus/share_plus.dart';
import '../../i18n/strings.g.dart';
/// Dialog for sharing a watch together session with others
class SessionInviteDialog extends StatelessWidget {
final String sessionId;
@@ -33,9 +35,9 @@ class SessionInviteDialog extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Watch Together', style: theme.textTheme.titleLarge),
Text(t.watchTogether.title, style: theme.textTheme.titleLarge),
Text(
'$participantCount ${participantCount == 1 ? 'participant' : 'participants'}',
'$participantCount ${participantCount == 1 ? t.watchTogether.participant : t.watchTogether.participantsPlural}',
style: theme.textTheme.bodySmall?.copyWith(color: theme.colorScheme.onSurfaceVariant),
),
],
@@ -82,7 +84,7 @@ class SessionInviteDialog extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Session Code',
t.watchTogether.sessionCode,
style: theme.textTheme.bodySmall?.copyWith(color: theme.colorScheme.onSurfaceVariant),
),
const SizedBox(height: 4),
@@ -100,7 +102,7 @@ class SessionInviteDialog extends StatelessWidget {
IconButton(
onPressed: () => _copyToClipboard(context),
icon: const Icon(Symbols.content_copy),
tooltip: 'Copy code',
tooltip: t.watchTogether.copyCode,
),
],
),
@@ -110,7 +112,7 @@ class SessionInviteDialog extends StatelessWidget {
// Instructions
Text(
'Share this code with others to let them join your watch session.',
t.watchTogether.shareInstructions,
style: theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.onSurfaceVariant),
textAlign: TextAlign.center,
),
@@ -121,7 +123,7 @@ class SessionInviteDialog extends StatelessWidget {
FilledButton.icon(
onPressed: () => _share(context),
icon: const Icon(Symbols.share),
label: const Text('Share'),
label: Text(t.watchTogether.share),
),
],
),
@@ -132,12 +134,12 @@ class SessionInviteDialog extends StatelessWidget {
void _copyToClipboard(BuildContext context) {
Clipboard.setData(ClipboardData(text: sessionId));
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Session code copied to clipboard')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.watchTogether.codeCopied)));
}
void _share(BuildContext context) {
final text = 'Join my Watch Together session!\n\nSession Code: $sessionId';
Share.share(text, subject: 'Watch Together Invite');
final text = t.watchTogether.inviteText(sessionId: sessionId);
Share.share(text, subject: t.watchTogether.inviteSubject);
}
}
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import '../../i18n/strings.g.dart';
import '../models/watch_session.dart';
import '../providers/watch_together_provider.dart';
import 'session_invite_dialog.dart';
@@ -102,9 +103,9 @@ class _SessionIndicator extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(color: theme.colorScheme.primary, borderRadius: BorderRadius.circular(4)),
child: const Text(
'HOST',
style: TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold),
child: Text(
t.watchTogether.hostBadge,
style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold),
),
),
],
@@ -143,9 +144,9 @@ class _SessionMenuSheet extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Watch Together', style: theme.textTheme.titleMedium),
Text(t.watchTogether.title, style: theme.textTheme.titleMedium),
Text(
provider.isHost ? 'You are the host' : 'Watching with others',
provider.isHost ? t.watchTogether.youAreHost : t.watchTogether.watchingWithOthers,
style: theme.textTheme.bodySmall?.copyWith(color: theme.colorScheme.onSurfaceVariant),
),
],
@@ -159,7 +160,9 @@ class _SessionMenuSheet extends StatelessWidget {
borderRadius: BorderRadius.circular(12),
),
child: Text(
provider.controlMode == ControlMode.hostOnly ? 'Host controls' : 'Anyone controls',
provider.controlMode == ControlMode.hostOnly
? t.watchTogether.hostControls
: t.watchTogether.anyoneControls,
style: theme.textTheme.labelSmall,
),
),
@@ -171,7 +174,7 @@ class _SessionMenuSheet extends StatelessWidget {
const SizedBox(height: 8),
// Participants list
Text('Participants', style: theme.textTheme.titleSmall),
Text(t.watchTogether.participants, style: theme.textTheme.titleSmall),
const SizedBox(height: 8),
...provider.participants.map(
(p) => ListTile(
@@ -184,7 +187,7 @@ class _SessionMenuSheet extends StatelessWidget {
),
),
title: Text(p.displayName),
subtitle: p.isHost ? const Text('Host') : null,
subtitle: p.isHost ? Text(t.watchTogether.host) : null,
trailing: p.isBuffering
? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
: null,
@@ -201,7 +204,7 @@ class _SessionMenuSheet extends StatelessWidget {
if (provider.isHost && provider.sessionId != null)
ListTile(
leading: const Icon(Symbols.share),
title: const Text('Invite others'),
title: Text(t.watchTogether.inviteOthers),
onTap: () {
Navigator.pop(context);
showSessionInviteDialog(
@@ -216,7 +219,7 @@ class _SessionMenuSheet extends StatelessWidget {
ListTile(
leading: Icon(Symbols.logout, color: theme.colorScheme.error),
title: Text(
provider.isHost ? 'End session' : 'Leave session',
provider.isHost ? t.watchTogether.endSession : t.watchTogether.leaveSession,
style: TextStyle(color: theme.colorScheme.error),
),
onTap: () {
@@ -235,21 +238,19 @@ class _SessionMenuSheet extends StatelessWidget {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(provider.isHost ? 'End Session?' : 'Leave Session?'),
title: Text(provider.isHost ? t.watchTogether.endSessionQuestion : t.watchTogether.leaveSessionQuestion),
content: Text(
provider.isHost
? 'This will end the watch session for all participants.'
: 'You will be disconnected from the watch session.',
provider.isHost ? t.watchTogether.endSessionConfirmOverlay : t.watchTogether.leaveSessionConfirmOverlay,
),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Cancel')),
TextButton(onPressed: () => Navigator.pop(context), child: Text(t.common.cancel)),
FilledButton(
onPressed: () {
Navigator.pop(context);
provider.leaveSession();
onLeaveSession?.call();
},
child: Text(provider.isHost ? 'End Session' : 'Leave'),
child: Text(provider.isHost ? t.watchTogether.endSession : t.watchTogether.leave),
),
],
),
@@ -277,16 +278,16 @@ class SyncingIndicator extends StatelessWidget {
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(color: Colors.black54, borderRadius: BorderRadius.circular(20)),
child: const Row(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
),
SizedBox(width: 8),
Text('Syncing...', style: TextStyle(color: Colors.white, fontSize: 12)),
const SizedBox(width: 8),
Text(t.watchTogether.syncing, style: const TextStyle(color: Colors.white, fontSize: 12)),
],
),
),