From 863b5e2ea08bc1cfef28bd5d8b92e037dce61a04 Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:50:22 +0900 Subject: [PATCH] =?UTF-8?q?WIP=2082=20=EB=B3=B4=EC=B6=A9=20(15=20=EC=A7=80?= =?UTF-8?q?=EC=A0=81):=20=EA=B0=99=EC=9D=80=20=EC=9D=B4=EB=A6=84=EC=9D=84?= =?UTF-8?q?=20=EB=8D=AE=EC=96=B4=EC=93=B4=20=ED=8C=8C=EC=9D=BC=EC=9D=80=20?= =?UTF-8?q?"=EB=8D=AE=EC=96=B4=EC=93=B4=20=ED=8C=8C=EC=9D=BC=20n=EA=B0=9C?= =?UTF-8?q?=EB=8A=94=20=EB=90=98=EB=8F=8C=EB=A6=AC=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=8A=B5=EB=8B=88=EB=8B=A4"=20(=ED=8F=B4=EB=8D=94=EB=9D=BC?= =?UTF-8?q?=EA=B3=A0=20=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B2=8C)=20+=2078?= =?UTF-8?q?=20=EC=8B=9C=ED=97=98=20=ED=9D=94=EB=93=A4=EB=A6=BC=20(?= =?UTF-8?q?=EA=B2=80=ED=86=A0=20=EB=8C=80=EA=B8=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 끌어 놓기 이동에서 같은 이름을 덮어쓴 파일이 "합친 폴더 n개는 무엇을 옮겼는지 몰라…" 로 나왔다. 파일이면 따로 센다. 되돌리지 않는 까닭: 원래 파일은 이미 덮어써져 없고, 되돌리면 대상에 아무것도 남지 않는다. 되돌릴 것이 하나도 없으면 [되돌리기] 알림을 띄우지 않고 끝난 알림 ([폴더 열기]) 그대로. - 78 시험: 알림은 목록을 다시 읽은 뒤에 뜨므로 파일이 보일 때가 아니라 알림까지 기다린다 (전체 시험 중 한 번 흔들림). - 시험: explorer_test 82 (새 파일 하나 + 덮어쓴 파일 하나 → "덮어쓴 파일 1개", "합친 폴더" 없음). Co-Authored-By: Claude Opus 5.5 --- assets/l10n/en.json | 1 + assets/l10n/ja.json | 1 + assets/l10n/zh-Hans.json | 1 + lib/ui/explorer_page.dart | 9 ++++++++- test/explorer_test.dart | 25 ++++++++++++++++++++++++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/assets/l10n/en.json b/assets/l10n/en.json index ca146e3..b7ef40f 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -567,6 +567,7 @@ "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "Detected language: {0} - if it is wrong, make them again with another language", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "Downloaded only if the detected language differs from the subtitle language {0}", "같은 시리즈 (번호만 다른 파일)": "Same series (files that differ only by number)", + "같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "{0} files that replaced a file with the same name won't be undone.", "같은 이름이 이미 있습니다": "An item with the same name already exists", "같은 이름이 이미 있습니다: {0}": "Already exists with the same name: {0}", "같은 이름이 이미 있음": "Name already exists", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index 35491df..ef5f2fe 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -567,6 +567,7 @@ "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "検出した言語: {0} - 違っていれば別の言語で作り直してください", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "検出した言語が作成する言語と異なる場合のみダウンロード {0}", "같은 시리즈 (번호만 다른 파일)": "同じシリーズ(番号だけ違うファイル)", + "같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "同じ名前を上書きしたファイル {0} 件は元に戻しません。", "같은 이름이 이미 있습니다": "同じ名前のものが既にあります", "같은 이름이 이미 있습니다: {0}": "同じ名前が既にあります: {0}", "같은 이름이 이미 있음": "同じ名前が既にあります", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index c2fefaf..87b985e 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -567,6 +567,7 @@ "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "检测到的语言:{0} - 如有误,请用其他语言重新生成", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "仅当检测到的语言与要生成的语言不同时下载 {0}", "같은 시리즈 (번호만 다른 파일)": "同一系列(仅编号不同的文件)", + "같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.": "{0} 个覆盖了同名文件的文件不会撤销。", "같은 이름이 이미 있습니다": "已存在同名项目", "같은 이름이 이미 있습니다: {0}": "已存在同名项目: {0}", "같은 이름이 이미 있음": "同名项已存在", diff --git a/lib/ui/explorer_page.dart b/lib/ui/explorer_page.dart index 0cfd560..0a36578 100644 --- a/lib/ui/explorer_page.dart +++ b/lib/ui/explorer_page.dart @@ -3542,7 +3542,8 @@ class _ExplorerPageState extends State { void _offerUndoMove(DragLoad load, TransferJob job, Set existed) { // (원래 폴더 → 지금 경로들) final back = >{}; - var notUndoable = 0; + // 되돌리지 않는 것: 합친 폴더 (robocopy - 무엇을 옮겼는지 모름) · 같은 이름을 덮어쓴 파일 (원래 파일은 이미 없음, 15 지적) + var notUndoable = 0, overwritten = 0; final pairs = job.made.length == load.paths.length ? [for (var i = 0; i < load.paths.length; i++) (load.paths[i], job.made[i])] : [ @@ -3555,6 +3556,11 @@ class _ExplorerPageState extends State { back.putIfAbsent(vDirname(src), () => []).add(now); continue; } + // 같은 이름을 덮어쓴 파일: 되돌리면 대상에 아무것도 남지 않으므로 그대로 둔다 + if (!vIsDirSync(now)) { + overwritten++; + continue; + } // 합친 폴더: 그 안에서 실제로 옮긴 파일만 final files = [for (final f in job.movedFiles) if (isSameOrInside(f, src) && !samePath(f, src)) f]; if (files.isEmpty) { @@ -3575,6 +3581,7 @@ class _ExplorerPageState extends State { content: Text([ trf('{0}개를 옮겼습니다.', [moved]), if (notUndoable > 0) trf('합친 폴더 {0}개는 무엇을 옮겼는지 몰라 되돌리지 않습니다.', [notUndoable]), + if (overwritten > 0) trf('같은 이름을 덮어쓴 파일 {0}개는 되돌리지 않습니다.', [overwritten]), ].join(' ')), action: SnackBarAction(label: tr('되돌리기'), onPressed: () => unawaited(_undoMove(_panes[load.from], back))), )); diff --git a/test/explorer_test.dart b/test/explorer_test.dart index bb9b82b..d3ea565 100644 --- a/test/explorer_test.dart +++ b/test/explorer_test.dart @@ -889,7 +889,8 @@ void main() { await tester.enterText(find.widgetWithText(TextField, '이름 틀 (확장자는 그대로)'), 'Ep[C]'); await tester.pump(); await act(tester, () => tester.tap(find.widgetWithText(FilledButton, '바꾸기 (2개)'))); - await settle(tester, () => File(p.join(left, 'Ep02.txt')).existsSync() && find.text('Ep02.txt').evaluate().isNotEmpty); + // 알림은 목록을 다시 읽은 뒤에 뜬다 - 알림까지 기다린다 (PC 가 바쁠 때 한 번 흔들림) + await settle(tester, () => File(p.join(left, 'Ep02.txt')).existsSync() && find.text('2개의 이름을 바꿨습니다.').evaluate().isNotEmpty); // 목록 차례 (이름순: b.txt, doc.txt) 대로 번호 expect(File(p.join(left, 'Ep01.txt')).readAsStringSync(), 'b'); expect(File(p.join(left, 'Ep02.txt')).readAsStringSync(), 'hello'); @@ -1062,6 +1063,28 @@ void main() { expect(File(p.join(right, 'doc.txt')).existsSync(), isFalse); }); + testWidgets('이동 → 같은 이름을 덮어쓴 파일은 되돌리지 않는다고 파일로 알림 (15 지적)', (tester) async { + File(p.join(right, 'doc.txt')).writeAsStringSync('old'); + File(p.join(left, 'e.txt')).writeAsStringSync('e'); + c.settings + ..explorerDropAction = 'move' + ..copyConflict = 'overwrite'; + await open(tester); + await act(tester, () => tester.tap(find.text('선택').first)); + await act(tester, () => tester.tap(markOf('doc.txt'))); + await act(tester, () => tester.tap(markOf('e.txt'))); + await calm(tester); + await mouseDrag(tester, tester.getCenter(find.text('e.txt').first), rightOf(tester, 'right')); + await settle(tester, () => find.widgetWithText(FilledButton, '이동').evaluate().isNotEmpty); + await act(tester, () => tester.tap(find.widgetWithText(FilledButton, '이동'))); + await settle(tester, () => find.text('되돌리기').evaluate().isNotEmpty); + expect(find.textContaining('같은 이름을 덮어쓴 파일 1개는 되돌리지 않습니다'), findsOneWidget); + expect(find.textContaining('합친 폴더'), findsNothing); + ScaffoldMessenger.of(tester.element(find.byType(ExplorerPage))).clearSnackBars(); + await calm(tester); + await tester.pump(const Duration(seconds: 2)); // 진행 막대가 내려가는 시간 (1.2초) 까지 + }); + testWidgets('이동 → [되돌리기]: 새로 생긴 것은 통째로, 이미 있던 폴더에 합친 것은 옮긴 파일만', (tester) async { // 오른쪽에 이미 sub 폴더 (원래 파일 하나) - 합치기 File(p.join(right, 'sub', 'mine.txt'))