feat: copy session code to clipboard

close #279
This commit is contained in:
edde746
2026-01-16 16:25:08 +01:00
parent 0290adcb6d
commit 9071eab3ae
10 changed files with 125 additions and 16 deletions
+16 -2
View File
@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 7
/// Strings: 3764 (537 per locale)
/// Strings: 3771 (538 per locale)
///
/// Built on 2026-01-15 at 19:06 UTC
/// Built on 2026-01-16 at 11:07 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@@ -962,6 +962,7 @@ class _StringsWatchTogetherEn {
String get joinInstructions => 'Enter the session code shared by the host to join their watch session.';
String get failedToCreate => 'Failed to create session';
String get failedToJoin => 'Failed to join session';
String get sessionCodeCopied => 'Session code copied to clipboard';
}
// Path: downloads
@@ -1899,6 +1900,7 @@ class _StringsWatchTogetherDe implements _StringsWatchTogetherEn {
@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';
@override String get sessionCodeCopied => 'Sitzungscode in Zwischenablage kopiert';
}
// Path: hotkeys.actions
@@ -2813,6 +2815,7 @@ class _StringsWatchTogetherIt implements _StringsWatchTogetherEn {
@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';
@override String get sessionCodeCopied => 'Codice sessione copiato negli appunti';
}
// Path: hotkeys.actions
@@ -3704,6 +3707,7 @@ class _StringsWatchTogetherKo implements _StringsWatchTogetherEn {
@override String get joinInstructions => '호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.';
@override String get failedToCreate => '세션 생성 실패';
@override String get failedToJoin => '세션 참여 실패';
@override String get sessionCodeCopied => '세션 코드가 클립보드에 복사되었습니다';
}
// Path: downloads
@@ -4641,6 +4645,7 @@ class _StringsWatchTogetherNl implements _StringsWatchTogetherEn {
@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';
@override String get sessionCodeCopied => 'Sessiecode gekopieerd naar klembord';
}
// Path: hotkeys.actions
@@ -5555,6 +5560,7 @@ class _StringsWatchTogetherSv implements _StringsWatchTogetherEn {
@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';
@override String get sessionCodeCopied => 'Sessionskod kopierad till urklipp';
}
// Path: hotkeys.actions
@@ -6469,6 +6475,7 @@ class _StringsWatchTogetherZh implements _StringsWatchTogetherEn {
@override String get joinInstructions => '输入主持人分享的会话代码以加入他们的观看会话。';
@override String get failedToCreate => '创建会话失败';
@override String get failedToJoin => '加入会话失败';
@override String get sessionCodeCopied => '会话代码已复制到剪贴板';
}
// Path: hotkeys.actions
@@ -7053,6 +7060,7 @@ extension on Translations {
case 'watchTogether.joinInstructions': return 'Enter the session code shared by the host to join their watch session.';
case 'watchTogether.failedToCreate': return 'Failed to create session';
case 'watchTogether.failedToJoin': return 'Failed to join session';
case 'watchTogether.sessionCodeCopied': return 'Session code copied to clipboard';
case 'downloads.title': return 'Downloads';
case 'downloads.manage': return 'Manage';
case 'downloads.tvShows': return 'TV Shows';
@@ -7613,6 +7621,7 @@ extension on _StringsDe {
case 'watchTogether.joinInstructions': return 'Gib den vom Host geteilten Sitzungscode ein, um seiner Schausitzung beizutreten.';
case 'watchTogether.failedToCreate': return 'Sitzung konnte nicht erstellt werden';
case 'watchTogether.failedToJoin': return 'Sitzung konnte nicht beigetreten werden';
case 'watchTogether.sessionCodeCopied': return 'Sitzungscode in Zwischenablage kopiert';
default: return null;
}
}
@@ -8159,6 +8168,7 @@ extension on _StringsIt {
case 'watchTogether.joinInstructions': return 'Inserisci il codice sessione condiviso dall\'host per unirti alla loro sessione di visione.';
case 'watchTogether.failedToCreate': return 'Impossibile creare la sessione';
case 'watchTogether.failedToJoin': return 'Impossibile unirsi alla sessione';
case 'watchTogether.sessionCodeCopied': return 'Codice sessione copiato negli appunti';
default: return null;
}
}
@@ -8691,6 +8701,7 @@ extension on _StringsKo {
case 'watchTogether.joinInstructions': return '호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.';
case 'watchTogether.failedToCreate': return '세션 생성 실패';
case 'watchTogether.failedToJoin': return '세션 참여 실패';
case 'watchTogether.sessionCodeCopied': return '세션 코드가 클립보드에 복사되었습니다';
case 'downloads.title': return '다운로드';
case 'downloads.manage': return '관리';
case 'downloads.tvShows': return 'TV 프로그램';
@@ -9251,6 +9262,7 @@ extension on _StringsNl {
case 'watchTogether.joinInstructions': return 'Voer de sessiecode in die door de host is gedeeld om deel te nemen aan hun kijksessie.';
case 'watchTogether.failedToCreate': return 'Sessie maken mislukt';
case 'watchTogether.failedToJoin': return 'Sessie deelnemen mislukt';
case 'watchTogether.sessionCodeCopied': return 'Sessiecode gekopieerd naar klembord';
default: return null;
}
}
@@ -9797,6 +9809,7 @@ extension on _StringsSv {
case 'watchTogether.joinInstructions': return 'Ange sessionskoden som delats av värden för att gå med i deras tittarsession.';
case 'watchTogether.failedToCreate': return 'Det gick inte att skapa session';
case 'watchTogether.failedToJoin': return 'Det gick inte att gå med i session';
case 'watchTogether.sessionCodeCopied': return 'Sessionskod kopierad till urklipp';
default: return null;
}
}
@@ -10343,6 +10356,7 @@ extension on _StringsZh {
case 'watchTogether.joinInstructions': return '输入主持人分享的会话代码以加入他们的观看会话。';
case 'watchTogether.failedToCreate': return '创建会话失败';
case 'watchTogether.failedToJoin': return '加入会话失败';
case 'watchTogether.sessionCodeCopied': return '会话代码已复制到剪贴板';
default: return null;
}
}
+2 -1
View File
@@ -587,7 +587,8 @@
"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"
"failedToJoin": "Failed to join session",
"sessionCodeCopied": "Session code copied to clipboard"
},
"downloads": {
"title": "Downloads",
+2 -1
View File
@@ -605,6 +605,7 @@
"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"
"failedToJoin": "Sitzung konnte nicht beigetreten werden",
"sessionCodeCopied": "Sitzungscode in Zwischenablage kopiert"
}
}
+2 -1
View File
@@ -605,6 +605,7 @@
"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"
"failedToJoin": "Impossibile unirsi alla sessione",
"sessionCodeCopied": "Codice sessione copiato negli appunti"
}
}
+2 -1
View File
@@ -589,7 +589,8 @@
"codeMustBe8Chars": "세션 코드는 반드시 8자리여야 합니다",
"joinInstructions": "호스트가 공유한 세션 코드를 입력하여 시청 세션에 참여하세요.",
"failedToCreate": "세션 생성 실패",
"failedToJoin": "세션 참여 실패"
"failedToJoin": "세션 참여 실패",
"sessionCodeCopied": "세션 코드가 클립보드에 복사되었습니다"
},
"downloads": {
"title": "다운로드",
+2 -1
View File
@@ -605,6 +605,7 @@
"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"
"failedToJoin": "Sessie deelnemen mislukt",
"sessionCodeCopied": "Sessiecode gekopieerd naar klembord"
}
}
+2 -1
View File
@@ -605,6 +605,7 @@
"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"
"failedToJoin": "Det gick inte att gå med i session",
"sessionCodeCopied": "Sessionskod kopierad till urklipp"
}
}
+2 -1
View File
@@ -605,6 +605,7 @@
"codeMustBe8Chars": "会话代码必须是8个字符",
"joinInstructions": "输入主持人分享的会话代码以加入他们的观看会话。",
"failedToCreate": "创建会话失败",
"failedToJoin": "加入会话失败"
"failedToJoin": "加入会话失败",
"sessionCodeCopied": "会话代码已复制到剪贴板"
}
}
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
@@ -218,13 +219,7 @@ class _ActiveSessionContent extends StatelessWidget {
watchTogether.isHost ? t.watchTogether.hostingSession : t.watchTogether.inSession,
style: theme.textTheme.titleMedium,
),
Text(
'${t.watchTogether.sessionCode}: ${session.sessionId}',
style: theme.textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
color: theme.colorScheme.onSurfaceVariant,
),
),
_SessionCodeRow(sessionId: session.sessionId),
],
),
),
@@ -360,3 +355,48 @@ class _ActiveSessionContent extends StatelessWidget {
}
}
}
/// Tappable session code row with copy functionality
class _SessionCodeRow extends StatelessWidget {
final String sessionId;
const _SessionCodeRow({required this.sessionId});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return InkWell(
onTap: () => _copySessionCode(context),
borderRadius: BorderRadius.circular(4),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${t.watchTogether.sessionCode}: $sessionId',
style: theme.textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
color: theme.colorScheme.onSurfaceVariant,
),
),
const SizedBox(width: 4),
Icon(
Symbols.content_copy_rounded,
size: 14,
color: theme.colorScheme.onSurfaceVariant,
),
],
),
),
);
}
void _copySessionCode(BuildContext context) {
Clipboard.setData(ClipboardData(text: sessionId));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(t.watchTogether.sessionCodeCopied)),
);
}
}
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
@@ -168,6 +169,46 @@ class _SessionMenuSheet extends StatelessWidget {
],
),
// Session code with copy button
if (provider.sessionId != null) ...[
const SizedBox(height: 12),
InkWell(
onTap: () => _copySessionCode(context, provider.sessionId!),
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${t.watchTogether.sessionCode}: ',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
Text(
provider.sessionId!,
style: theme.textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
Icon(
Symbols.content_copy_rounded,
size: 16,
color: theme.colorScheme.onSurfaceVariant,
),
],
),
),
),
],
const SizedBox(height: 16),
const Divider(),
const SizedBox(height: 8),
@@ -218,6 +259,13 @@ class _SessionMenuSheet extends StatelessWidget {
);
}
void _copySessionCode(BuildContext context, String sessionId) {
Clipboard.setData(ClipboardData(text: sessionId));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(t.watchTogether.sessionCodeCopied)),
);
}
void _confirmLeave(BuildContext context) {
showDialog(
context: context,