diff --git a/lib/ui/explorer_page.dart b/lib/ui/explorer_page.dart index 32399c7..1657d93 100644 --- a/lib/ui/explorer_page.dart +++ b/lib/ui/explorer_page.dart @@ -908,11 +908,19 @@ class _ExplorerPageState extends State { Future _load(_Pane pane, String dir, {bool force = false}) async { if (!force && pane.cache.containsKey(dir)) return; - // X-plore 비교 f: 압축 안 (읽어 둔 목록에서) - if (_archiveOf(dir) != null) { - pane.cache[dir] = _sorted(_archiveList(dir), dir); - pane.changed(); - return; + // X-plore 비교 f: 압축 안 (읽어 둔 목록에서). 새로 고침이면 압축 파일이 바뀌었는지 보고 바뀌었으면 다시 읽는다 + final arc = _archiveOf(dir); + if (arc != null) { + if (force && !await _readArchive(arc)) { + pane.cache[dir] = const []; + pane.changed(); + return; + } + if (_archives.containsKey(arc)) { + pane.cache[dir] = _sorted(_archiveList(dir), dir); + pane.changed(); + return; + } } // 80: 다시 읽는 폴더는 안이 바뀌었을 수 있다 - 그 폴더와 위 폴더들의 크기를 잊는다 if (force) _sizes.forget(dir); @@ -2173,6 +2181,28 @@ class _ExplorerPageState extends State { /// 펼쳐 본 압축의 목록 (압축 경로 → 항목) final _archives = >{}; + /// 압축을 읽은 때의 (크기, 바뀐 때) - 바뀌었으면 다음에 펼치거나 새로 고칠 때 다시 읽는다 (관리자 지시 10/19) + final _archiveStamps = {}; + + static Future<(int, DateTime)?> _stampOf(String path) async { + try { + final st = await File(path).stat(); + if (st.type == FileSystemEntityType.notFound) return null; + return (st.size, st.modified); + } catch (_) { + return null; + } + } + + /// [arc] 의 읽어 둔 목록과 창들의 그 안 목록을 잊는다 (다시 읽게) + void _forgetArchive(String arc) { + _archives.remove(arc); + _archiveStamps.remove(arc); + for (final q in _panes) { + q.cache.removeWhere((k, _) => samePath(k, arc) || isSameOrInside(k, arc)); + } + } + /// 트리에서 펼칠 수 있는 압축 (이 기기의 파일 · 탐색기 화면) bool _canBrowseArchive(FileEntry e) => !widget.rsync && !e.isDir && !isDav(e.path) && archiveKindOf(e.path) != null; @@ -2196,7 +2226,13 @@ class _ExplorerPageState extends State { /// 압축의 목록을 읽어 둔다 (비밀번호가 걸린 7z 등은 [압축 풀기] 로 안내). 읽었으면 true Future _readArchive(String path) async { - if (_archives.containsKey(path)) return true; + final stamp = await _stampOf(path); + if (_archives.containsKey(path)) { + // 펼친 뒤 압축 파일이 바뀌었으면 (크기 · 바뀐 때) 다시 읽는다. 없어졌으면 잊는다 + if (stamp != null && stamp == _archiveStamps[path]) return true; + _forgetArchive(path); + if (stamp == null) return false; + } final kind = archiveKindOf(path)!; try { if (kind == ArchiveKind.zip) { @@ -2209,6 +2245,7 @@ class _ExplorerPageState extends State { } _archives[path] = await list7z(exe, path); } + if (stamp != null) _archiveStamps[path] = stamp; return true; } on ArchivePasswordException { _snack(tr('비밀번호가 걸린 압축은 안을 미리 볼 수 없습니다 - [압축 풀기] 로 푸세요')); diff --git a/test/explorer_test.dart b/test/explorer_test.dart index d70bf15..cbbd623 100644 --- a/test/explorer_test.dart +++ b/test/explorer_test.dart @@ -358,6 +358,28 @@ void main() { await calm(tester); }); + testWidgets('X-plore f 보충: 펼친 뒤 압축 파일이 바뀌면 새로 고칠 때 목록을 다시 읽는다 (관리자 지시 10/19)', (tester) async { + final zip = p.join(left, 'pack.zip'); + File(zip).writeAsBytesSync(ZipEncoder().encode(Archive()..addFile(ArchiveFile.string('old.txt', 'old')))); + await open(tester); + await settle(tester, () => find.text('pack.zip').evaluate().isNotEmpty); + await act(tester, () => tester.tap(chevronOf('pack.zip').first)); + await settle(tester, () => find.text('old.txt').evaluate().isNotEmpty); + expect(find.text('old.txt'), findsOneWidget); + // 다른 프로그램이 압축을 바꿈 (크기 · 바뀐 때가 달라짐) + await tester.runAsync(() async { + await Future.delayed(const Duration(milliseconds: 1100)); + File(zip).writeAsBytesSync(ZipEncoder().encode(Archive() + ..addFile(ArchiveFile.string('new.txt', 'new content')) + ..addFile(ArchiveFile.string('more.txt', 'more')))); + }); + await act(tester, () => tester.sendKeyEvent(LogicalKeyboardKey.f5)); + await settle(tester, () => find.text('new.txt').evaluate().isNotEmpty); + expect(find.text('new.txt'), findsOneWidget); + expect(find.text('more.txt'), findsOneWidget); + expect(find.text('old.txt'), findsNothing); + }); + testWidgets('X-plore g · h: 폴더 메뉴 [격자로 보기] (길게 = 그 자리로) · 파일 메뉴 [글 뷰어로 보기]', (tester) async { File(p.join(left, 'sub', 'pic.png')).writeAsBytesSync([0x89, 0x50]); await open(tester);