이동 카드 저장 창은 '이 이동을' · '받는 쪽이 더 새것이면 건너뛰기' 를 Rsync 탭에도 (233)

- 233 (버그): 이동 카드인데 '이 복사를' 로 묻던 것
- 관리자 지시: 229 설정이 Rsync 화면 · 모니터링에서도 쓰이므로 Rsync 설정 탭에서도 같은 스위치

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음5
RyuJongJin 2026-10-12 00:53:37 +09:00
parent 4cad606fe1
commit 5a0bc0ec50
6 changed files with 51 additions and 9 deletions

View File

@ -1480,6 +1480,7 @@
"이 언어 지우기": "Remove this language",
"이 위치 (네트워크 드라이브 · 네트워크 공유 · USB 메모리 등) 에는 휴지통이 없어 바로 지워집니다.": "This location (network drive, network share, USB memory etc.) has no Recycle Bin, so items are deleted right away.",
"이 이동 버튼 지우기": "Delete this move button",
"이 이동을 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?": "These options will be used the next time this move runs. Run it now with the new options?",
"이 파일에 맞는 자막 우선 (영상 해시)": "Prefer subtitles that match this file (video hash)",
"이 파일용": "For this file",
"이 파일을 열 수 있는 앱이 없습니다.": "No app can open this file.",
@ -1767,6 +1768,7 @@
"지금 것만 취소 (다음 것부터 이어서)": "Cancel only the current one (continue with the next)",
"지금 것만 취소: {0}": "Cancelled only the current one: {0}",
"지금 도는 복사는 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "The running copy uses the previous options. Stop it and run again with the new options?",
"지금 도는 이동은 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "The running move is using the previous options. Stop it and run again with the new options?",
"지금 마스터 (또는 최상) 비밀번호": "Current master (or top) password",
"지금 맞추기": "Sync now",
"지금 맞추는 중입니다. 끝난 뒤에 하세요.": "Syncing right now. Try again when it finishes.",

View File

@ -1480,6 +1480,7 @@
"이 언어 지우기": "この言語を削除",
"이 위치 (네트워크 드라이브 · 네트워크 공유 · USB 메모리 등) 에는 휴지통이 없어 바로 지워집니다.": "この場所 (ネットワークドライブ・ネットワーク共有・USB メモリなど) にはごみ箱がないため、すぐに削除されます。",
"이 이동 버튼 지우기": "この移動ボタンを削除",
"이 이동을 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?": "この移動を次に行うときにこのオプションを使います。今すぐ新しいオプションで実行しますか?",
"이 파일에 맞는 자막 우선 (영상 해시)": "このファイルに合う字幕を優先(動画ハッシュ)",
"이 파일용": "このファイル用",
"이 파일을 열 수 있는 앱이 없습니다.": "このファイルを開けるアプリがありません。",
@ -1767,6 +1768,7 @@
"지금 것만 취소 (다음 것부터 이어서)": "今のものだけ取り消し (次から続ける)",
"지금 것만 취소: {0}": "今のものだけ取り消し: {0}",
"지금 도는 복사는 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "実行中のコピーは前のオプションで動いています。止めて新しいオプションで再実行しますか?",
"지금 도는 이동은 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "実行中の移動は前のオプションで動いています。止めて新しいオプションでやり直しますか?",
"지금 마스터 (또는 최상) 비밀번호": "現在のマスター (または最上位) パスワード",
"지금 맞추기": "今すぐ同期",
"지금 맞추는 중입니다. 끝난 뒤에 하세요.": "同期中です。終わってから行ってください。",

View File

@ -1480,6 +1480,7 @@
"이 언어 지우기": "删除此语言",
"이 위치 (네트워크 드라이브 · 네트워크 공유 · USB 메모리 등) 에는 휴지통이 없어 바로 지워집니다.": "此位置 (网络驱动器 · 网络共享 · U 盘等) 没有回收站,会直接删除。",
"이 이동 버튼 지우기": "删除此移动按钮",
"이 이동을 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?": "下次执行此移动时将使用这些选项。现在用新选项执行吗?",
"이 파일에 맞는 자막 우선 (영상 해시)": "优先匹配此文件的字幕(视频哈希)",
"이 파일용": "适用于此文件",
"이 파일을 열 수 있는 앱이 없습니다.": "没有可以打开此文件的应用。",
@ -1767,6 +1768,7 @@
"지금 것만 취소 (다음 것부터 이어서)": "仅取消当前项(从下一个继续)",
"지금 것만 취소: {0}": "仅取消当前项:{0}",
"지금 도는 복사는 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "正在运行的复制使用的是之前的选项。停止并用新选项重新运行吗?",
"지금 도는 이동은 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?": "正在进行的移动使用的是之前的选项。要停止并用新选项重新执行吗?",
"지금 마스터 (또는 최상) 비밀번호": "当前主密码 (或最高密码)",
"지금 맞추기": "立即同步",
"지금 맞추는 중입니다. 끝난 뒤에 하세요.": "正在同步。请等结束后再进行。",

View File

@ -151,13 +151,7 @@ class _CopySyncSettingsState extends State<CopySyncSettings> {
onChanged: (v) => c.updateSettings((x) => x.copyConflict = v ?? 'ask'),
),
),
// 229: 폴더 안의 것을 맞출 때 (모니터링의 현재 방식 · WebDAV) - rsync 의 -u 와 같다
SwitchListTile(
value: s.copySkipNewer,
onChanged: (v) => c.updateSettings((x) => x.copySkipNewer = v),
title: Text(tr('받는 쪽이 더 새것이면 건너뛰기')),
subtitle: Text(tr('현재 방식 · robocopy · WebDAV 로 복사 · 이동할 때 (rsync 의 -u, robocopy 의 /XO 와 같음). 건너뛴 파일은 이동이라도 원본에 남깁니다')),
),
_skipNewerTile(),
SettingTile(
title: Text(tr('속도 제한 (KB/s)')),
subtitle: Text(tr('0 = 제한 없음. 모든 방법에 적용: rsync --bwlimit, 현재 방식은 앱이 조절, robocopy 는 /IPG 로 비슷하게. '
@ -178,6 +172,14 @@ class _CopySyncSettingsState extends State<CopySyncSettings> {
}
/// Rsync 화면: rsync 옵션 · rsync 가져오기 · 실시간 동기화 (lsync)
/// 229: 받는 쪽이 더 새것이면 건너뛰기 - 파일 탐색기 · Rsync 탭 두 곳에 같은 설정 (Rsync 화면 · 모니터링에서도 쓰여 찾기 쉽게)
Widget _skipNewerTile() => SwitchListTile(
value: c.settings.copySkipNewer,
onChanged: (v) => c.updateSettings((x) => x.copySkipNewer = v),
title: Text(tr('받는 쪽이 더 새것이면 건너뛰기')),
subtitle: Text(tr('현재 방식 · robocopy · WebDAV 로 복사 · 이동할 때 (rsync 의 -u, robocopy 의 /XO 와 같음). 건너뛴 파일은 이동이라도 원본에 남깁니다')),
);
Widget _rsyncPart() {
final s = c.settings;
final desk = Platform.isWindows;
@ -186,6 +188,7 @@ class _CopySyncSettingsState extends State<CopySyncSettings> {
_options(tr('rsync 옵션'), tr('예: -avPog (보관 · 자세히 · 진행 · 소유자 · 그룹). 속도 제한은 파일 탐색기의 속도 제한을 함께 씀. '
'새로 맞추는 폴더 쌍에 씁니다 - 이미 실행한 쌍은 기억한 옵션을 쓰며 모니터링 > 복사 · rsync 에서 따로 고칩니다'),
s.rsyncOptions, defaultRsyncOptions, (x, v) => x.rsyncOptions = v),
_skipNewerTile(),
SettingTile(
title: Text(tr('rsync 가져오기')),
subtitle: Text(_checking

View File

@ -435,8 +435,13 @@ class _CopyCardState extends State<_CopyCard> {
scrollable: true,
title: Text(tr('옵션을 저장했습니다')),
content: Text(running
? tr('지금 도는 복사는 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?')
: tr('이 복사를 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?')),
// 233: 이동 카드는 "이동" 으로
? (t.move
? tr('지금 도는 이동은 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?')
: tr('지금 도는 복사는 앞의 옵션으로 돌고 있습니다. 멈추고 새 옵션으로 다시 실행할까요?'))
: (t.move
? tr('이 이동을 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?')
: tr('이 복사를 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?'))),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('현재 유지'))),
FilledButton(onPressed: () => Navigator.pop(ctx, true), child: Text(tr('설정 반영 후 실행'))),

View File

@ -11,6 +11,7 @@ import 'package:jj_mkvmaker/core/cron_window.dart';
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/copy_sync_settings.dart' show CopySyncSettings;
import 'package:jj_mkvmaker/ui/monitor_page.dart';
import 'package:path/path.dart' as p;
@ -300,6 +301,7 @@ void main() {
await tester.tap(find.text('저장'));
await tester.pumpAndSettle();
expect(find.text('옵션을 저장했습니다'), findsOneWidget);
expect(find.text('이 복사를 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?'), findsOneWidget);
expect(find.text('설정 반영 후 실행'), findsOneWidget);
await tester.tap(find.text('현재 유지'));
await tester.pumpAndSettle();
@ -313,4 +315,30 @@ void main() {
expect(find.text('지금 맞추기'), findsOneWidget);
expect(find.text('복사 · rsync 로 이동'), findsOneWidget);
});
testWidgets('233: 이동 카드의 저장 창은 "이 이동을" · 229 설정은 Rsync 탭에도 있다', (tester) async {
final tmp = Directory.systemTemp.createTempSync('jj_mon233_');
addTearDown(() => tmp.deleteSync(recursive: true));
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings.copyTasks = [CopyTask(id: '1', sources: [tmp.path], dest: p.join(tmp.path, '..'), move: true, method: 'builtin')];
tester.view.physicalSize = const Size(1500, 1000);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
await tester.pumpWidget(MaterialApp(home: MonitorPage(c: c)));
await tester.pump();
await tester.enterText(find.widgetWithText(TextField, '속도 제한'), '500');
await tester.pump();
await tester.tap(find.text('저장'));
await tester.pumpAndSettle();
expect(find.text('이 이동을 다시 할 때 이 옵션을 씁니다. 지금 새 옵션으로 실행할까요?'), findsOneWidget);
await tester.tap(find.text('현재 유지'));
await tester.pumpAndSettle();
// Rsync 탭의 설정에도 같은 스위치
await tester.pumpWidget(MaterialApp(home: Scaffold(body: SingleChildScrollView(child: CopySyncSettings(c: c, rsync: true)))));
await tester.pump();
expect(find.text('받는 쪽이 더 새것이면 건너뛰기'), findsOneWidget);
await tester.tap(find.text('받는 쪽이 더 새것이면 건너뛰기'));
await tester.pump();
expect(c.settings.copySkipNewer, isFalse);
});
}