From 37d7c0da317cd634b1bcb5fd3abf9ba6c47bdbce Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Sun, 11 Oct 2026 22:35:05 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=8B=88=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EC=97=90=20=EC=8B=A4=EC=A0=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=ED=95=A0=20=EA=B2=83=20=C2=B7=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20/=20=EB=B3=B5=EC=82=AC=20(209)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 관리자 지시: 카드의 옵션 칸은 저장된 원문이라 이동 카드는 "-avPog", 복사 카드는 "… --remove-source-files" (실제로는 빠짐) 로 거꾸로 읽혔다. 칸 옆에 "이동 · 실제 실행: rsync -avPog --remove-source-files" / "복사 · 실제 실행: rsync -avPog" 를 보이고, 복사 카드 칸에 원본 지우기 옵션이 있으면 쓰지 않는다고 알린다. Co-Authored-By: Claude Opus 5.5 --- assets/l10n/en.json | 2 ++ assets/l10n/ja.json | 2 ++ assets/l10n/zh-Hans.json | 2 ++ lib/ui/monitor_page.dart | 26 ++++++++++++++++++++++++-- test/dismiss_test.dart | 21 +++++++++++++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/assets/l10n/en.json b/assets/l10n/en.json index 616f737..dbc0e09 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -981,6 +981,7 @@ "복사 끝 ({0}): {1}개 → {2}": "Copy done ({0}): {1} → {2}", "복사 모니터링": "Copy monitor", "복사 실패 ({0}): {1}": "Copy failed ({0}): {1}", + "복사 작업이라 칸의 원본 지우기 옵션 (--remove-source-files · /MOV) 은 쓰지 않습니다. 옮기려면 Rsync 화면에서 [원본 파일 지우기] 를 켜세요": "This is a copy task, so source-removing options in the field (--remove-source-files · /MOV) are not used. To move, turn on [Remove source files] on the Rsync screen", "복사(Ctrl+C)한 주소 자동 다운로드": "Auto-download copied (Ctrl+C) URLs", "복사하는 중": "Copying", "복사할": "copy", @@ -1174,6 +1175,7 @@ "실시간 동기화가 없습니다. [추가] 하거나 복사 · rsync 탭에서 [lsync 로 이동] 하세요.": "No live sync. [Add] one, or use [Move to lsync] in the copy · rsync tab.", "실시간 동기화를 지울까요?": "Delete this live sync?", "실시간 동기화의 [최종 정리]": "[Final cleanup] in live sync", + "실제 실행: {0}": "Actually runs: {0}", "실패": "Failed", "실패 · {0}": "Failed · {0}", "실패: {0}": "Failed: {0}", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index 03c3a3c..2dbb471 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -981,6 +981,7 @@ "복사 끝 ({0}): {1}개 → {2}": "コピー完了 ({0}): {1} 件 → {2}", "복사 모니터링": "コピーのモニタリング", "복사 실패 ({0}): {1}": "コピー失敗 ({0}): {1}", + "복사 작업이라 칸의 원본 지우기 옵션 (--remove-source-files · /MOV) 은 쓰지 않습니다. 옮기려면 Rsync 화면에서 [원본 파일 지우기] 를 켜세요": "コピー作業のため、欄の元ファイル削除オプション (--remove-source-files · /MOV) は使いません。移動するには Rsync 画面で [元ファイルを削除] をオンにしてください", "복사(Ctrl+C)한 주소 자동 다운로드": "コピー(Ctrl+C)した URL を自動ダウンロード", "복사하는 중": "コピー中", "복사할": "コピーする", @@ -1174,6 +1175,7 @@ "실시간 동기화가 없습니다. [추가] 하거나 복사 · rsync 탭에서 [lsync 로 이동] 하세요.": "リアルタイム同期はありません。[追加] するか、コピー · rsync タブで [lsync へ移動] してください。", "실시간 동기화를 지울까요?": "このリアルタイム同期を削除しますか?", "실시간 동기화의 [최종 정리]": "リアルタイム同期の [最終整理]", + "실제 실행: {0}": "実際の実行: {0}", "실패": "失敗", "실패 · {0}": "失敗 · {0}", "실패: {0}": "失敗: {0}", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index f50da36..32b87df 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -981,6 +981,7 @@ "복사 끝 ({0}): {1}개 → {2}": "复制完成 ({0}): {1} 个 → {2}", "복사 모니터링": "复制监控", "복사 실패 ({0}): {1}": "复制失败 ({0}): {1}", + "복사 작업이라 칸의 원본 지우기 옵션 (--remove-source-files · /MOV) 은 쓰지 않습니다. 옮기려면 Rsync 화면에서 [원본 파일 지우기] 를 켜세요": "这是复制任务,栏中的删除源文件选项(--remove-source-files · /MOV)不会使用。要移动,请在 Rsync 界面打开 [删除源文件]", "복사(Ctrl+C)한 주소 자동 다운로드": "自动下载复制(Ctrl+C)的地址", "복사하는 중": "正在复制", "복사할": "复制", @@ -1174,6 +1175,7 @@ "실시간 동기화가 없습니다. [추가] 하거나 복사 · rsync 탭에서 [lsync 로 이동] 하세요.": "没有实时同步。请 [添加],或在 复制 · rsync 标签中 [移到 lsync]。", "실시간 동기화를 지울까요?": "删除此实时同步吗?", "실시간 동기화의 [최종 정리]": "实时同步的 [最终整理]", + "실제 실행: {0}": "实际执行:{0}", "실패": "失败", "실패 · {0}": "失败 · {0}", "실패: {0}": "失败: {0}", diff --git a/lib/ui/monitor_page.dart b/lib/ui/monitor_page.dart index b78b63a..ec2b536 100644 --- a/lib/ui/monitor_page.dart +++ b/lib/ui/monitor_page.dart @@ -19,11 +19,20 @@ import 'copy_sync_settings.dart' show addLiveSyncPairDialog, editLiveSyncPairDia import 'path_label.dart'; import 'rsync_setup.dart'; import 'schedule_editor.dart'; -import '../core/sync_preview.dart' show withoutSourceRemovingOptions; +import '../core/sync_preview.dart' show withoutSourceRemovingOptions, optionsRemoveSource; import 'sync_preview_view.dart' show confirmDeletingRun; import 'theme.dart'; /// 모니터링 (파일 탐색기 > 모니터링): 복사 · rsync 와 lsync (실시간 동기화) 를 따로 보여 준다. +/// 178 · 209: 실제로 실행할 방법 · 옵션 (원본 지우기 옵션은 빼고, 이동일 때만 그 방법의 원본 지우기를 붙인다) +String effectiveRunText(String method, String options, {required bool move}) { + final name = method == 'builtin' ? tr('현재 방식') : method; + if (method == 'builtin') return name; + final opts = withoutSourceRemovingOptions(options); + final extra = move ? (method == 'robocopy' ? ' /MOVE' : method == 'rsync' ? ' --remove-source-files' : '') : ''; + return '$name $opts$extra'.trim(); +} + class MonitorPage extends StatelessWidget { final AppController c; final int initialTab; @@ -376,7 +385,7 @@ class _CopyCardState extends State<_CopyCard> { content: Text(trf('칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?', [ '${_method == 'builtin' ? tr('현재 방식') : _method} ${_options.text.trim()}', // 178: 실제로 쓰는 옵션 (원본 지우기는 이동일 때만) - '${t.method == 'builtin' ? tr('현재 방식') : t.method} ${withoutSourceRemovingOptions(t.options)}${t.move ? (t.method == 'robocopy' ? ' /MOVE' : t.method == 'rsync' ? ' --remove-source-files' : '') : ''}', + effectiveRunText(t.method, t.options, move: t.move), ])), actions: [ TextButton(onPressed: () => Navigator.pop(ctx), child: Text(tr('취소'))), @@ -540,6 +549,19 @@ class _CopyCardState extends State<_CopyCard> { onChanged: (_) => setState(() {}), ), ), + // 209: 실제로 실행할 것 - 이동 / 복사를 분명히 (칸의 원본 지우기 옵션은 이동일 때만 쓰인다) + SizedBox( + width: 460, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ + Text( + '${t.move ? tr('이동') : tr('복사')} · ${trf('실제 실행: {0}', [effectiveRunText(_method, _options.text.trim(), move: t.move)])}', + style: TextStyle(fontSize: 12, color: t.move ? Colors.orangeAccent : JjColors.textDim), + ), + if (!t.move && optionsRemoveSource(_options.text)) + Text(tr('복사 작업이라 칸의 원본 지우기 옵션 (--remove-source-files · /MOV) 은 쓰지 않습니다. 옮기려면 Rsync 화면에서 [원본 파일 지우기] 를 켜세요'), + style: const TextStyle(fontSize: 12, color: Colors.orangeAccent)), + ]), + ), SizedBox( width: 130, child: TextField( diff --git a/test/dismiss_test.dart b/test/dismiss_test.dart index f408b81..8548860 100644 --- a/test/dismiss_test.dart +++ b/test/dismiss_test.dart @@ -230,6 +230,27 @@ void main() { await tester.pumpAndSettle(); }); + testWidgets('209: 모니터링 카드는 실제로 실행할 것을 이동 / 복사와 함께 보인다 (복사 카드 칸의 원본 지우기 옵션은 쓰지 않는다고 알림)', (tester) async { + expect(effectiveRunText('rsync', '-avPog', move: true), 'rsync -avPog --remove-source-files'); + expect(effectiveRunText('rsync', '-avPog --remove-source-files', move: false), 'rsync -avPog'); + expect(effectiveRunText('robocopy', '/E /MOV', move: true), 'robocopy /E /MOVE'); + final a = p.join(tmp.path, 'ca'), b = p.join(tmp.path, 'cb'); + Directory(a).createSync(recursive: true); + Directory(b).createSync(recursive: true); + c.settings.copyTasks = [ + CopyTask(id: '1', sources: [a], dest: b, contents: true, method: 'rsync', options: '-avPog --remove-source-files'), + CopyTask(id: '2', sources: [b], dest: a, contents: true, move: true, method: 'rsync', options: '-avPog'), + ]; + tester.view.physicalSize = const Size(1500, 1200); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.reset); + await tester.pumpWidget(MaterialApp(home: MonitorPage(c: c))); + await tester.pump(); + expect(find.text('복사 · 실제 실행: rsync -avPog'), findsOneWidget); + expect(find.textContaining('복사 작업이라 칸의 원본 지우기 옵션'), findsOneWidget); + expect(find.text('이동 · 실제 실행: rsync -avPog --remove-source-files'), findsOneWidget); + }); + testWidgets('112 · 114: 모니터링 작업 - 짧은 경로, 저장하지 않은 고침이 있으면 [실행] 할 때 묻는다 (저장하면 그 옵션 · 지우기면 미리 보기)', (tester) async { final src = p.join(tmp.path, 'Download', 'movies'), dst = p.join(tmp.path, 'backup', 'movies');