79 lines
3.3 KiB
Dart
79 lines
3.3 KiB
Dart
import '../core/file_ops.dart' show outermostPaths, samePath, transferProblem;
|
|
import '../core/name_clash.dart';
|
|
import '../core/vfs.dart' show vBasename, vDirname, vJoin, vStat;
|
|
import '../l10n/tr.dart';
|
|
|
|
/// 약속 (E5b): 복사 · 이동을 시작하기 전 계획 ([planTransfer]) - CopyCenter.start 앞 단계.
|
|
/// 입력 = 원본들 · 대상 폴더 · 이동인지, 출력 = [TransferPlan] (실제로 보낼 것 · 건너뛸 것 · 무엇을 물을지 · 막는 문제).
|
|
/// 오류 없음 (막는 문제는 [TransferPlan.problem] 글로).
|
|
/// - 고른 폴더 안의 것은 한 번만 (바깥 것만).
|
|
/// - 135: 같은 폴더로 - 이동인데 일부만 이미 그 폴더에 있으면 그것만 건너뛰고 나머지를 옮긴다.
|
|
/// 모두 이미 그 폴더면 이동은 할 것이 없고 ([TransferPlan.nothingToMove]), 복사는 사본을 만들지 묻는다 ([TransferPlan.askCopyHere]).
|
|
/// - [findClashes]: 대상에 같은 이름이 있는 원본 (크기 · 바뀐 날 함께, 같은 폴더로 복사는 늘 새 이름이라 뺌).
|
|
/// - 다시 쓰는 곳: 탐색기 [복사] · [이동] · 끌어 놓기 · 붙여넣기 · 찾기 결과 복사.
|
|
class TransferPlan {
|
|
const TransferPlan({
|
|
required this.sources,
|
|
required this.here,
|
|
required this.skippedHere,
|
|
required this.nothingToMove,
|
|
required this.askCopyHere,
|
|
required this.problem,
|
|
});
|
|
|
|
/// 실제로 보낼 것
|
|
final List<String> sources;
|
|
|
|
/// 이미 대상 폴더에 있는 원본
|
|
final List<String> here;
|
|
|
|
/// 이동에서 이미 그 폴더에 있어 건너뛰는 것
|
|
final List<String> skippedHere;
|
|
final bool nothingToMove;
|
|
final bool askCopyHere;
|
|
|
|
/// 시작하지 않는 이유 (원본 · 대상이 없음, 폴더를 자기 안으로 등) - 없으면 null
|
|
final String? problem;
|
|
}
|
|
|
|
TransferPlan planTransfer(List<String> sources, String dest, {required bool move}) {
|
|
sources = outermostPaths(sources);
|
|
final here = [for (final x in sources) if (samePath(vDirname(x), dest)) x];
|
|
var skipped = const <String>[];
|
|
var rest = sources;
|
|
if (move && here.isNotEmpty && here.length < sources.length) {
|
|
skipped = here;
|
|
rest = [for (final x in sources) if (!here.contains(x)) x];
|
|
}
|
|
final all = here.isNotEmpty && skipped.isEmpty && (move || here.length == sources.length);
|
|
return TransferPlan(
|
|
sources: rest,
|
|
here: here,
|
|
skippedHere: skipped,
|
|
nothingToMove: all && move,
|
|
askCopyHere: all && !move,
|
|
problem: all && move ? null : transferProblem(rest, dest, move: move),
|
|
);
|
|
}
|
|
|
|
/// 48 · 172: 대상 폴더에 같은 이름이 있는 원본 - 두 파일의 크기 · 바뀐 날을 함께 (어느 쪽이 새것인지 보고 고르게)
|
|
Future<List<NameClash>> findClashes(List<String> sources, String dest) async {
|
|
final out = <NameClash>[];
|
|
for (final s in sources) {
|
|
if (samePath(vDirname(s), dest)) continue;
|
|
try {
|
|
final there = await vStat(vJoin(dest, vBasename(s)));
|
|
if (there == null) continue;
|
|
final here = await vStat(s);
|
|
out.add((src: s, here: here, there: there));
|
|
} catch (_) {}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/// 154: 항목 이름 (앞의 3개 + "외 n개")
|
|
String namesOf(List<String> paths) {
|
|
final names = [for (final x in paths.take(3)) vBasename(x)].join(', ');
|
|
return paths.length > 3 ? trf('{0} 외 {1}개', [names, paths.length - 3]) : names;
|
|
}
|