미리 보기에 덮어쓸 것을 눈에 띄게 (211)

관리자 지시: 대상에 내용이 다른 같은 이름이 있으면 목록에 "~ 이름" 으로만 보였다. 요약을 "덮어씀 n" 으로,
"받는 쪽에서 n개를 덮어씁니다 (내용이 다른 같은 이름 - 원래 것은 없어짐)" 주황 줄과 목록의 "(덮어씀)" 을 더한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_mkv
RyuJongJin 2026-10-11 22:53:25 +09:00
parent 64ce867612
commit c0397e9fe1
5 changed files with 52 additions and 2 deletions

View File

@ -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",

View File

@ -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 モデル",
"받다 만 다운로드": "ダウンロード途中のファイル",

View File

@ -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 模型",
"받다 만 다운로드": "未完成的下载",

View File

@ -97,11 +97,12 @@ class _SyncPreviewViewState extends State<SyncPreviewView> {
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<SyncPreviewView> {
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<SyncPreviewView> {
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<SyncPreviewView> {
fontFamily: 'monospace',
color: switch (x.action) {
PreviewAction.delete => Colors.redAccent,
PreviewAction.update => Colors.orangeAccent,
PreviewAction.onlyTarget => JjColors.textDim,
_ => null,
},

View File

@ -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);
});
}