diff --git a/assets/l10n/en.json b/assets/l10n/en.json index e154ab1..628ec15 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -46,6 +46,7 @@ "'사진' 모델로 바꿔 다시": "Switch to 'Photos' and redo", "(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(Languages cannot be added because AI translation is unavailable on this device)", "({0}개 지움)": "(delete {0})", + "(덮어씀)": "(overwritten)", "(동영상을 세 번 누르면 옮깁니다)": "(Tapping a video three times moves it)", "(받는 쪽에만 있음)": "(only on receiving side)", "(비어 있음)": "(empty)", @@ -325,6 +326,7 @@ "{0} 번역 중": "Translating {0}", "{0} 번역 중 {1}%": "Translating {0} {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "Use the YouTube sign-in cookies of the {0} browser (Chrome · Edge may need to be closed to be read)", + "{0} 새로 {1} · 덮어씀 {2}": "{0} new {1} · overwrite {2}", "{0} 새로 {1} · 바뀜 {2}": "{0} new {1} · changed {2}", "{0} 설치": "Install {0}", "{0} 순으로 정렬{1}": "Sort by {0}{1}", @@ -903,6 +905,7 @@ "받는 중인 다운로드가 없습니다.": "Nothing is downloading.", "받는 쪽에만 있음 {0} (그대로 둠)": "Only on receiving side {0} (kept)", "받는 쪽에서 {0}개가 지워집니다 (--delete, 되돌릴 수 없음)": "{0} items will be deleted on the receiving side (--delete, cannot be undone)", + "받는 쪽에서 {0}개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)": "{0} files on the receiving side will be overwritten (same name, different content - the original is lost)", "받는 크기: 약 {0}MB · 받은 파일 · AI 모델 · 설정은 그대로 둡니다": "Download size: about {0}MB · downloaded files · AI models · settings are kept", "받다 만 AI 모델": "Unfinished AI models", "받다 만 다운로드": "Unfinished downloads", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index 1c82010..aa713d7 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -46,6 +46,7 @@ "'사진' 모델로 바꿔 다시": "「写真」モデルに変えてやり直す", "(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(この端末では AI 翻訳が使えないため言語を追加できません)", "({0}개 지움)": "({0} 個を削除)", + "(덮어씀)": "(上書き)", "(동영상을 세 번 누르면 옮깁니다)": "(動画を 3 回タップすると移動します)", "(받는 쪽에만 있음)": "(受け取る側にだけある)", "(비어 있음)": "(空)", @@ -325,6 +326,7 @@ "{0} 번역 중": "{0} を翻訳中", "{0} 번역 중 {1}%": "{0} を翻訳中 {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "{0} ブラウザーの YouTube ログインクッキーを使う(Chrome・Edge はブラウザーを閉じないと読めないことがあります)", + "{0} 새로 {1} · 덮어씀 {2}": "{0} 新規 {1} · 上書き {2}", "{0} 새로 {1} · 바뀜 {2}": "{0} 新規 {1}・変更 {2}", "{0} 설치": "{0} のインストール", "{0} 순으로 정렬{1}": "{0} 順に並べ替え{1}", @@ -903,6 +905,7 @@ "받는 중인 다운로드가 없습니다.": "ダウンロード中のものはありません。", "받는 쪽에만 있음 {0} (그대로 둠)": "受け取る側にだけある {0} (そのまま)", "받는 쪽에서 {0}개가 지워집니다 (--delete, 되돌릴 수 없음)": "受け取る側で {0} 個が削除されます (--delete、元に戻せません)", + "받는 쪽에서 {0}개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)": "受け取る側の {0} 件を上書きします (同じ名前で内容が違うもの - 元のものはなくなります)", "받는 크기: 약 {0}MB · 받은 파일 · AI 모델 · 설정은 그대로 둡니다": "ダウンロードサイズ: 約 {0}MB・ダウンロードしたファイル・AI モデル・設定はそのまま", "받다 만 AI 모델": "ダウンロード途中の AI モデル", "받다 만 다운로드": "ダウンロード途中のファイル", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index ac12912..bfa536a 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -46,6 +46,7 @@ "'사진' 모델로 바꿔 다시": "改用“照片”模型重新处理", "(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(此设备无法使用 AI 翻译,因此无法添加语言)", "({0}개 지움)": "(删除 {0} 个)", + "(덮어씀)": "(覆盖)", "(동영상을 세 번 누르면 옮깁니다)": "(连按视频三次会移动它)", "(받는 쪽에만 있음)": "(仅在接收方)", "(비어 있음)": "(空)", @@ -325,6 +326,7 @@ "{0} 번역 중": "正在翻译 {0}", "{0} 번역 중 {1}%": "正在翻译 {0} {1}%", "{0} 브라우저의 YouTube 로그인 쿠키 사용 (Chrome · Edge 는 브라우저를 닫아야 읽힐 수 있음)": "使用 {0} 浏览器的 YouTube 登录 Cookie(Chrome · Edge 可能需要关闭浏览器才能读取)", + "{0} 새로 {1} · 덮어씀 {2}": "{0} 新增 {1} · 覆盖 {2}", "{0} 새로 {1} · 바뀜 {2}": "{0} 新增 {1} · 更改 {2}", "{0} 설치": "安装 {0}", "{0} 순으로 정렬{1}": "按{0}排序{1}", @@ -903,6 +905,7 @@ "받는 중인 다운로드가 없습니다.": "没有正在进行的下载。", "받는 쪽에만 있음 {0} (그대로 둠)": "仅在接收方 {0} (保留)", "받는 쪽에서 {0}개가 지워집니다 (--delete, 되돌릴 수 없음)": "接收方将删除 {0} 个项目 (--delete,无法撤销)", + "받는 쪽에서 {0}개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)": "将覆盖接收端的 {0} 个文件(同名但内容不同 - 原文件将丢失)", "받는 크기: 약 {0}MB · 받은 파일 · AI 모델 · 설정은 그대로 둡니다": "下载大小: 约 {0}MB · 已下载的文件 · AI 模型 · 设置均保留", "받다 만 AI 모델": "未下载完的 AI 模型", "받다 만 다운로드": "未完成的下载", diff --git a/lib/ui/sync_preview_view.dart b/lib/ui/sync_preview_view.dart index 4bade58..a3c1829 100644 --- a/lib/ui/sync_preview_view.dart +++ b/lib/ui/sync_preview_view.dart @@ -97,11 +97,12 @@ class _SyncPreviewViewState extends State { int n(PreviewAction a, [bool? right]) => items.where((x) => x.action == a && (right == null || x.toRight == right)).length; final dels = n(PreviewAction.delete); + final overwrites = n(PreviewAction.update); final more = items.length >= widget.limit; final parts = [ for (final right in [true, false]) if (n(PreviewAction.add, right) + n(PreviewAction.update, right) > 0) - trf('{0} 새로 {1} · 바뀜 {2}', [right ? '→' : '←', n(PreviewAction.add, right), n(PreviewAction.update, right)]), + trf('{0} 새로 {1} · 덮어씀 {2}', [right ? '→' : '←', n(PreviewAction.add, right), n(PreviewAction.update, right)]), if (n(PreviewAction.onlyTarget) > 0) trf('받는 쪽에만 있음 {0} (그대로 둠)', [n(PreviewAction.onlyTarget)]), ]; return Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ @@ -117,6 +118,10 @@ class _SyncPreviewViewState extends State { if (dels > 0) Text(trf('받는 쪽에서 {0}개가 지워집니다 (--delete, 되돌릴 수 없음)', [dels]), style: const TextStyle(fontSize: 12, color: Colors.redAccent, fontWeight: FontWeight.w600)), + // 211: 내용이 다른 같은 이름은 받는 쪽 파일이 바뀐다 - 목록의 "~" 만으로는 알아채기 어려웠다 + if (overwrites > 0) + Text(trf('받는 쪽에서 {0}개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)', [overwrites]), + style: const TextStyle(fontSize: 12, color: Colors.orangeAccent, fontWeight: FontWeight.w600)), if (items.isNotEmpty) Container( margin: const EdgeInsets.only(top: 6), @@ -134,7 +139,7 @@ class _SyncPreviewViewState extends State { Text( switch (x.action) { PreviewAction.add => '${_arrow(x)} + ${x.rel}${x.isDir ? '/' : ' (${formatSize(x.size)})'}', - PreviewAction.update => '${_arrow(x)} ~ ${x.rel} (${formatSize(x.size)})', + PreviewAction.update => '${_arrow(x)} ~ ${x.rel} (${formatSize(x.size)}) ${tr('(덮어씀)')}', PreviewAction.onlyTarget => ' = ${x.rel}${x.isDir ? '/' : ''} ${tr('(받는 쪽에만 있음)')}', PreviewAction.delete => '${_arrow(x)} − ${x.rel}${x.isDir ? '/' : ''} ${tr('(지워짐)')}', }, @@ -143,6 +148,7 @@ class _SyncPreviewViewState extends State { fontFamily: 'monospace', color: switch (x.action) { PreviewAction.delete => Colors.redAccent, + PreviewAction.update => Colors.orangeAccent, PreviewAction.onlyTarget => JjColors.textDim, _ => null, }, diff --git a/test/sync_preview_view_test.dart b/test/sync_preview_view_test.dart new file mode 100644 index 0000000..8d85c6e --- /dev/null +++ b/test/sync_preview_view_test.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:jj_mkvmaker/core/sync_preview.dart'; +import 'package:jj_mkvmaker/ui/sync_preview_view.dart'; + +/// 211: 미리 보기에서 덮어쓰는 것 (내용이 다른 같은 이름) 을 눈에 띄게 +void main() { + testWidgets('211: 덮어쓸 것이 있으면 "덮어씀 n" · 주황 경고 줄 · 목록에 (덮어씀)', (tester) async { + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: SyncPreviewView( + compute: () async => const [ + PreviewItem('new.txt', PreviewAction.add, toRight: true, size: 3), + PreviewItem('diff.txt', PreviewAction.update, toRight: true, size: 5), + ], + ), + ), + )); + await tester.pumpAndSettle(); + expect(find.text('→ 새로 1 · 덮어씀 1'), findsOneWidget); + expect(find.text('받는 쪽에서 1개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)'), findsOneWidget); + expect(find.textContaining('~ diff.txt'), findsOneWidget); + expect(find.textContaining('(덮어씀)'), findsOneWidget); + }); + + testWidgets('211: 덮어쓸 것이 없으면 경고 줄 없음', (tester) async { + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: SyncPreviewView(compute: () async => const [PreviewItem('new.txt', PreviewAction.add, toRight: true, size: 3)]), + ), + )); + await tester.pumpAndSettle(); + expect(find.textContaining('덮어씁니다'), findsNothing); + }); +}