이동 확인 창의 명령 줄은 실제로 실행할 것 (230)

- 버그 (테스터 지적): 모니터링 이동 카드 [실행] 확인 창이 칸의 옵션을 그대로 보여 --remove-source-files 가 빠져 보였다
- effectiveRunText 를 sync_preview_view 로 옮겨 확인 창도 같은 글을 쓴다 (원본 지우기 옵션은 이동일 때만)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_mkv
RyuJongJin 2026-10-11 23:39:13 +09:00
parent c070486c84
commit 8c2ddc3385
3 changed files with 37 additions and 11 deletions

View File

@ -19,19 +19,11 @@ 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, optionsRemoveSource;
import 'sync_preview_view.dart' show confirmDeletingRun;
import '../core/sync_preview.dart' show optionsRemoveSource;
import 'sync_preview_view.dart' show confirmDeletingRun, effectiveRunText;
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;

View File

@ -182,6 +182,15 @@ bool taskDeletes(CopyTask t) {
/// 104: 지우기가 들어 있는 작업은 어디서 실행하든 (모니터링 [실행] · 옵션 저장 뒤 실행 · 최종 정리) Rsync 화면과 같은 미리 보기를 거친다.
/// 지울 목록이 나온 뒤에만 [실행] 이 켜진다. 지우기가 없으면 묻지 않고 true
/// 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();
}
/// [includeMove] (210): 이동 (원본 파일 지우기) 도 미리 보기 · 확인을 거친다 - 모니터링의 [실행] 처럼 따로 묻는 창이 없을 때.
/// [skipNewer] (229): 앱이 직접 할 때 (현재 방식 · WebDAV) 받는 쪽이 더 새것이면 건너뛰는지 (환경 설정)
Future<bool> confirmDeletingRun(BuildContext context, CopyTask t, {bool includeMove = false, bool skipNewer = false}) async {
@ -210,7 +219,8 @@ Future<bool> confirmDeletingRun(BuildContext context, CopyTask t, {bool includeM
Text('→ ${shortPath(dstOf(s))}', style: const TextStyle(fontWeight: FontWeight.w600)),
Text('${vDisplay(s)} → ${vDisplay(dstOf(s))}', style: const TextStyle(fontSize: 11, color: JjColors.textDim)),
],
Text('${t.method} ${t.options}', style: const TextStyle(fontSize: 12, fontFamily: 'monospace', color: JjColors.textDim)),
// 230: 칸에 적힌 옵션이 아니라 실제로 실행할 것 (원본 지우기 옵션은 이동일 때만 붙는다)
Text(effectiveRunText(t.method, t.options, move: t.move), style: const TextStyle(fontSize: 12, fontFamily: 'monospace', color: JjColors.textDim)),
// 210: 이동이면 실행 뒤 원본에서 지워진다는 것을 분명히
if (t.move)
Padding(

View File

@ -193,6 +193,30 @@ void main() {
expect(find.text('아직 실행 안 함'), findsOneWidget);
});
testWidgets('230: 이동 확인 창의 명령 줄은 실제로 실행할 것 (rsync 는 --remove-source-files 를 붙이고, 복사면 원본 지우기 옵션을 뺀다)', (tester) async {
final src = p.join(tmp.path, 'r'), dst = p.join(tmp.path, 'rd');
File(p.join(src, 'a.txt'))
..createSync(recursive: true)
..writeAsStringSync('a');
Directory(dst).createSync();
bool? r;
final mv = CopyTask(id: '1', sources: [src], dest: dst, contents: true, move: true, method: 'rsync', options: '-avPog');
await host(tester, (ctx) async => r = await confirmDeletingRun(ctx, mv, includeMove: true));
await settle(tester, () => find.textContaining('비교하는 중').evaluate().isEmpty, rounds: 200);
expect(find.text('rsync -avPog --remove-source-files'), findsOneWidget);
expect(find.text('rsync -avPog'), findsNothing);
await tester.tap(find.text('취소').last);
await tester.pumpAndSettle();
expect(r, isFalse);
// 복사 (지우기 있음) 인데 칸에 원본 지우기 옵션이 남아 있으면 - 실제로는 빼고 실행하므로 창에도 빼고
final cp = CopyTask(id: '2', sources: [src], dest: dst, contents: true, method: 'rsync', options: '-avPog --delete --remove-source-files');
await host(tester, (ctx) async => r = await confirmDeletingRun(ctx, cp));
await settle(tester, () => find.textContaining('비교하는 중').evaluate().isEmpty, rounds: 200);
expect(find.text('rsync -avPog --delete'), findsOneWidget);
await tester.tap(find.text('취소').last);
await tester.pumpAndSettle();
});
testWidgets('105: 원본이 대상 안 + 창에서 [원본 파일 지우기] 로 지우기 옵션이 생기면 막는다', (tester) async {
final outer = p.join(tmp.path, 'O'), inner = p.join(outer, 'in');
File(p.join(inner, 'n.txt'))