WIP 264 · 265 이동 · 복사 끝: 알림에 "n개는 원본에 남음" · 펼쳐 둔 원본 · 대상 안쪽까지 다시 읽기 (없어진 폴더는 접음) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음6
parent
92919aae93
commit
8228d04a6e
|
|
@ -1407,6 +1407,30 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 265: 복사 · 이동 뒤 - 대상 · 원본의 위 폴더와, 펼쳐 둔 원본 · 대상 안쪽까지 두 창 모두 다시 읽는다.
|
||||||
|
/// (예전에는 원본의 위 폴더만 읽어, 합치다 남은 원본 폴더 아래에 옮겨진 파일이 계속 보였다) 없어진 폴더는 접는다
|
||||||
|
Future<void> _refreshAfterTransfer(List<String> sources, String dest) async {
|
||||||
|
for (final x in _panes) {
|
||||||
|
final dirs = {
|
||||||
|
dest,
|
||||||
|
...sources.map(vDirname),
|
||||||
|
for (final k in x.cache.keys)
|
||||||
|
if (isSameOrInside(k, dest) || sources.any((s) => isSameOrInside(k, s))) k,
|
||||||
|
};
|
||||||
|
for (final d in dirs) {
|
||||||
|
if (!mounted) return;
|
||||||
|
if (!x.cache.containsKey(d)) continue;
|
||||||
|
if (!await vExists(d)) {
|
||||||
|
x.cache.remove(d);
|
||||||
|
x.expanded.remove(d);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 180: 비우지 않고 새로 읽은 것으로 바꾼다 (자리 · 스크롤 그대로)
|
||||||
|
await _load(x, d, force: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 바뀐 폴더를 두 창 모두 다시 읽는다
|
/// 바뀐 폴더를 두 창 모두 다시 읽는다
|
||||||
Future<void> _refreshAll(Iterable<String> dirs) async {
|
Future<void> _refreshAll(Iterable<String> dirs) async {
|
||||||
for (final pane in _panes) {
|
for (final pane in _panes) {
|
||||||
|
|
@ -2050,7 +2074,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
if (!mounted) return false;
|
if (!mounted) return false;
|
||||||
// 180: 표시만 지우고 선택 모드는 그대로 (꺼지면 동그라미 칸 · 아래 막대가 사라져 자리가 바뀐다)
|
// 180: 표시만 지우고 선택 모드는 그대로 (꺼지면 동그라미 칸 · 아래 막대가 사라져 자리가 바뀐다)
|
||||||
pane.marked.clear();
|
pane.marked.clear();
|
||||||
await _refreshAll([dest, ...sources.map(p.dirname)]);
|
await _refreshAfterTransfer(sources, dest);
|
||||||
// 넣은 폴더가 창의 지금 폴더면 펼쳐서 새 항목이 보이게
|
// 넣은 폴더가 창의 지금 폴더면 펼쳐서 새 항목이 보이게
|
||||||
for (final x in _panes) {
|
for (final x in _panes) {
|
||||||
if (samePath(x.current, dest)) {
|
if (samePath(x.current, dest)) {
|
||||||
|
|
@ -2065,6 +2089,9 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
||||||
? trf('끝나지 못했습니다: {0}', [error])
|
? trf('끝나지 못했습니다: {0}', [error])
|
||||||
: [
|
: [
|
||||||
trf('{0}개 항목을 {1}', [job.made.length, move ? tr('옮겼습니다.') : tr('복사했습니다.')]),
|
trf('{0}개 항목을 {1}', [job.made.length, move ? tr('옮겼습니다.') : tr('복사했습니다.')]),
|
||||||
|
// 264: 작업 기록에만 있던 것도 알림에 (폴더를 합칠 때 받는 쪽이 더 새 파일 등)
|
||||||
|
if (move && job.leftInSource > 0) trf('{0}개는 원본에 남음 (건너뜀)', [job.leftInSource]),
|
||||||
|
if (!move && job.keptNewer > 0) trf('받는 쪽이 더 새것 {0}개 건너뜀', [job.keptNewer]),
|
||||||
if (job.skipped.isNotEmpty) trf('같은 이름이라 건너뜀: {0}', [_namesOf(job.skipped)]),
|
if (job.skipped.isNotEmpty) trf('같은 이름이라 건너뜀: {0}', [_namesOf(job.skipped)]),
|
||||||
if (skippedHere.isNotEmpty) trf('이미 이 폴더에 있어 건너뜀: {0}', [_namesOf(skippedHere)]),
|
if (skippedHere.isNotEmpty) trf('이미 이 폴더에 있어 건너뜀: {0}', [_namesOf(skippedHere)]),
|
||||||
].join(' · '));
|
].join(' · '));
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,38 @@ void main() {
|
||||||
expect(File(p.join(right, 'doc.txt')).readAsStringSync(), 'new');
|
expect(File(p.join(right, 'doc.txt')).readAsStringSync(), 'new');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('264 · 265: 폴더를 합쳐 옮긴 뒤 - 알림에 "원본에 남음", 펼쳐 둔 원본 폴더는 다시 읽어 옮겨진 파일이 보이지 않는다', (tester) async {
|
||||||
|
final d = p.join(left, 'D');
|
||||||
|
File(p.join(d, 'same.txt'))
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('old')
|
||||||
|
..setLastModifiedSync(DateTime(2026, 1, 1));
|
||||||
|
File(p.join(d, 'add.txt')).writeAsStringSync('a');
|
||||||
|
File(p.join(right, 'D', 'same.txt'))
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('NEWER');
|
||||||
|
c.settings.copyConflict = 'overwrite';
|
||||||
|
tester.view.physicalSize = const Size(1600, 900);
|
||||||
|
tester.view.devicePixelRatio = 1;
|
||||||
|
addTearDown(tester.view.reset);
|
||||||
|
await tester.runAsync(() => tester.pumpWidget(MaterialApp(home: ExplorerPage(c: c))));
|
||||||
|
await settle(tester, () => find.text('D').evaluate().length >= 2);
|
||||||
|
// 왼쪽 D 를 눌러 펼치고 (고른 것) 안의 add.txt 가 보이게
|
||||||
|
await tester.runAsync(() => tester.tap(find.text('D').first));
|
||||||
|
await settle(tester, () => find.text('add.txt').evaluate().isNotEmpty);
|
||||||
|
expect(find.text('add.txt'), findsOneWidget);
|
||||||
|
await tester.runAsync(() => tester.tap(find.text('이동').first));
|
||||||
|
await settle(tester, () => find.widgetWithText(FilledButton, '이동').evaluate().isNotEmpty);
|
||||||
|
await tester.runAsync(() => tester.tap(find.widgetWithText(FilledButton, '이동')));
|
||||||
|
await settle(tester, () => find.byType(LinearProgressIndicator).evaluate().isEmpty && find.byType(SnackBar).evaluate().isNotEmpty);
|
||||||
|
expect(File(p.join(right, 'D', 'add.txt')).existsSync(), isTrue);
|
||||||
|
expect(File(p.join(d, 'same.txt')).existsSync(), isTrue, reason: '받는 쪽이 더 새것이라 원본에 남음');
|
||||||
|
expect(find.textContaining('1개는 원본에 남음 (건너뜀)'), findsOneWidget, reason: '264: 알림에도');
|
||||||
|
expect(find.text('add.txt'), findsNothing, reason: '265: 원본 D 를 다시 읽음 (오른쪽 D 는 펼치지 않음)');
|
||||||
|
expect(find.text('same.txt'), findsOneWidget);
|
||||||
|
await calm(tester);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('48 보충: 처음 열면 아무것도 고르지 않은 상태 - 바로 [복사] 를 누르면 "복사할 항목을 고르세요" (폴더 통째로 복사하지 않음)', (tester) async {
|
testWidgets('48 보충: 처음 열면 아무것도 고르지 않은 상태 - 바로 [복사] 를 누르면 "복사할 항목을 고르세요" (폴더 통째로 복사하지 않음)', (tester) async {
|
||||||
tester.view.physicalSize = const Size(1600, 900);
|
tester.view.physicalSize = const Size(1600, 900);
|
||||||
tester.view.devicePixelRatio = 1;
|
tester.view.devicePixelRatio = 1;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue