From 53f5c432bb105e9ac918829abb2cb33f95cb490c Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Mon, 19 Oct 2026 20:47:58 +0900 Subject: [PATCH] =?UTF-8?q?WIP=20=EC=95=95=EC=B6=95=20=ED=8E=BC=EC=B9=98?= =?UTF-8?q?=EA=B8=B0:=20=ED=8E=BC=EC=B9=9C=20=EB=92=A4=20=EC=95=95?= =?UTF-8?q?=EC=B6=95=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=20=EB=B0=94=EB=80=8C?= =?UTF-8?q?=EB=A9=B4=20(=ED=81=AC=EA=B8=B0=20=C2=B7=20=EB=B0=94=EB=80=90?= =?UTF-8?q?=20=EB=95=8C)=20=ED=8E=BC=EC=B9=98=EA=B1=B0=EB=82=98=20?= =?UTF-8?q?=EC=83=88=EB=A1=9C=20=EA=B3=A0=EC=B9=A0=20=EB=95=8C=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=9D=84=20=EB=8B=A4=EC=8B=9C=20=EC=9D=BD=EC=9D=8C=20?= =?UTF-8?q?(=EA=B2=80=ED=86=A0=20=EB=8C=80=EA=B8=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 관리자 지시 (10/19, 사용자 "오늘 못했던 것 진행" 1번 - 압축 펼치기의 알려진 한계): 읽어 둔 압축 목록을 계속 써서, 다른 프로그램이 압축을 바꿔도 접었다 펼치거나 새로 고쳐도 예전 목록이 보였다. - 압축을 읽을 때의 (크기, 바뀐 때) 를 기억하고, 다시 펼칠 때 · 새로 고침 (F5 · [새로 고침] · 앱으로 돌아옴) 때 비교해 다르면 그 압축의 목록과 모든 창의 그 안 폴더 목록을 잊고 다시 읽는다. - 압축이 없어졌으면 목록을 잊고 그 안은 빈 목록으로 (예전 것을 보이지 않게). 시험: explorer_test (새 1: 펼친 뒤 압축을 바꾸고 F5 → 새 항목 · 예전 항목 없음) 62 통과, 임시 폴더 흔적 0 (tool/test_temp_check.ps1), analyze 문제 없음. Co-Authored-By: Claude Opus 5.5 --- lib/ui/explorer_page.dart | 49 ++++++++++++++++++++++++++++++++++----- test/explorer_test.dart | 22 ++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) 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);