import 'package:flutter/material.dart'; import '../../core/batch_rename.dart'; import '../../core/file_ops.dart'; import '../../core/vfs.dart'; import '../../l10n/tr.dart'; import '../batch_rename_dialog.dart'; import '../notice.dart'; import 'explorer_controller.dart'; import 'explorer_pane.dart'; import 'name_dialog.dart'; import 'write_guard.dart'; /// 약속 (E5d-6): 이름 바꾸기 - 하나 ([rename], 이름 창) · 여럿 ([batch], 78: 번호는 목록에 보이는 차례대로, 끝나면 [되돌리기]). /// 바꾼 뒤 목록을 다시 읽고 표시 · 초점 · 숨긴 목록을 새 이름으로. 읽기 전용인 곳은 [ExplorerGuard] 가 막고, 못 하면 까닭을 알림 class ExplorerRenames { ExplorerRenames(this.ctl, this.guard); final ExplorerController ctl; final ExplorerGuard guard; Future rename(BuildContext context, ExplorerPane pane, String path) async { if (guard.blockArchive([path])) return; final name = await askName(context, tr('이름 변경'), vBasename(path)); if (name == null || name == vBasename(path)) return; try { final now = await FileOps.rename(path, name); await ctl.followHidden(moved: [(path, now)]); await ctl.refreshAll([vDirname(path)]); for (final x in ctl.panes) { x.sel.rename(path, now); } pane.focused = now; pane.changed(); } catch (e) { ctl.host.snack(trf('이름을 바꿀 수 없습니다: {0}', [e])); } } /// 78: 일괄 이름 바꾸기 - 번호는 목록에 보이는 차례대로. 끝나면 [되돌리기] Future batch(BuildContext context, ExplorerPane pane, List paths) async { if (guard.blockArchive(paths)) return; int at(String x) { final i = (pane.cache[vDirname(x)] ?? const []).indexWhere((e) => samePath(e.path, x)); return i < 0 ? 1 << 30 : i; } final ordered = [...paths]..sort((a, b) { final d = vDirname(a).compareTo(vDirname(b)); return d != 0 ? d : at(a).compareTo(at(b)); }); final done = await showBatchRename(context, ordered, isDir: vIsDirSync, initial: RenameRule.fromJson(ctl.c.settings.batchRenameLast), onRun: (r) => ctl.c.updateSettings((s) => s.batchRenameLast = r.toJson())); if (done == null || done.isEmpty || !context.mounted) return; await _after(pane, done); if (!context.mounted) return; showNotice(ScaffoldMessenger.of(context), text: trf('{0}개의 이름을 바꿨습니다.', [done.length]), action: ( tr('되돌리기'), () async { try { final back = await runBatchRename([for (final (orig, now) in done) (now, vBasename(orig))]); if (context.mounted) await _after(pane, back); } on BatchRenameException catch (e) { ctl.host.snack(trf('되돌리지 못했습니다: {0}', [e])); } } )); } /// 바꾼 뒤: 목록을 다시 읽고, 표시 · 초점을 새 이름으로 Future _after(ExplorerPane pane, List<(String, String)> moved) async { await ctl.followHidden(moved: moved); await ctl.refreshAll({for (final (a, _) in moved) vDirname(a)}); for (final x in ctl.panes) { for (final (from, to) in moved) { x.sel.rename(from, to); if (x.focused != null && samePath(x.focused!, from)) x.focused = to; } x.changed(); } } }