탐색기: 앱으로 돌아오면 보이는 폴더를 다시 읽기 (232)

- 버그 (기기 확인): 다른 앱에서 바꾸고 돌아와도 예전 목록이 남았다 - 돌아올 때 [새로 고침] 과 같게 (WebDAV 는 빼고 - 관리자 판단 승인)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_mkv
RyuJongJin 2026-10-12 00:35:11 +09:00
parent b0c3a4cee2
commit 037ddf502a
2 changed files with 56 additions and 10 deletions

View File

@ -313,9 +313,36 @@ class _ExplorerPageState extends State<ExplorerPage> {
for (final pane in _panes) {
pane.addListener(_onPane);
}
_resumeReload = AppLifecycleListener(onResume: () => unawaited(_reloadOpen(localOnly: true)));
_init();
}
/// 232: 앱으로 돌아오면 (다른 앱 · 탐색기에서 파일을 바꾸고 오면) 보이는 폴더를 다시 읽는다
late final AppLifecycleListener _resumeReload;
bool _reloading = false;
/// 열려 있는 (보이는) 폴더를 두 창 모두 다시 읽는다 - [새로 고침] (183) 과 같다.
/// [localOnly]: 돌아올 때는 WebDAV 폴더는 빼고 (네트워크가 아직 안 붙었을 때 오류가 뜨지 않게 - [새로 고침] 으로는 읽음)
Future<void> _reloadOpen({bool localOnly = false}) async {
if (_reloading) return;
_reloading = true;
try {
// 180: 목록을 먼저 비우지 않고 새로 읽은 것으로 바꾼다 (비우면 목록이 사라졌다 생겨 스크롤 · 자리가 바뀐다)
for (final x in _panes) {
final open = {...x.expanded, x.current};
for (final d in open) {
if (!mounted) return;
if (localOnly && isDav(d)) continue;
await _load(x, d, force: true);
}
x.cache.removeWhere((k, _) => !open.contains(k));
x.changed();
}
} finally {
_reloading = false;
}
}
@override
void dispose() {
if (widget.rsync) {
@ -328,6 +355,7 @@ class _ExplorerPageState extends State<ExplorerPage> {
pane.dispose();
}
if (_allFiles != null) _life.dispose();
_resumeReload.dispose();
super.dispose();
}
@ -1372,16 +1400,8 @@ class _ExplorerPageState extends State<ExplorerPage> {
case ExplorerButton.both:
await _runRsync(right: true, left: true);
case ExplorerButton.refresh:
// 183: 두 창 모두 (밖에서 지운 파일이 다른 창에 남지 않게).
// 180: 목록을 먼저 비우지 않고 새로 읽은 것으로 바꾼다 (비우면 목록이 사라졌다 생겨 스크롤 · 자리가 바뀐다)
for (final x in _panes) {
final open = {...x.expanded, x.current};
for (final d in open) {
await _load(x, d, force: true);
}
x.cache.removeWhere((k, _) => !open.contains(k));
x.changed();
}
// 183: 두 창 모두 (밖에서 지운 파일이 다른 창에 남지 않게)
await _reloadOpen();
case ExplorerButton.play:
final t = _targets(pane);
final videos = t.where((x) => !vIsDirSync(x) && isVideoFile(x)).toList();

View File

@ -156,6 +156,32 @@ void main() {
await settle(tester, () => find.text('f03.txt').evaluate().isEmpty);
expect(find.text('f03.txt'), findsNothing);
});
testWidgets('232: 앱으로 돌아오면 보이는 폴더를 다시 읽는다 (다른 앱에서 지우고 · 만든 것이 바로 보이게)', (tester) async {
c.settings
..explorerLayout = 'dual'
..explorerPaths = [left, left];
tester.view.physicalSize = const Size(1280, 800);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
await tester.runAsync(() => tester.pumpWidget(MaterialApp(home: ExplorerPage(c: c))));
await settle(tester, () => find.text('f03.txt').evaluate().length == 2);
// 다른 앱으로 갔다가 (그사이 밖에서 지우고 만듦)
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.hidden);
await tester.runAsync(() async {
await File(p.join(left, 'f03.txt')).delete();
await File(p.join(left, '0_made_outside.txt')).writeAsString('m'); // 맨 위에 보이게 (목록이 길다)
});
await settle(tester, () => false, rounds: 5);
expect(find.text('f03.txt'), findsNWidgets(2), reason: '돌아오기 전에는 그대로');
// 돌아옴
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
await settle(tester, () => find.text('f03.txt').evaluate().isEmpty && find.text('0_made_outside.txt').evaluate().length == 2);
expect(find.text('f03.txt'), findsNothing);
expect(find.text('0_made_outside.txt'), findsNWidgets(2));
});
}
Finder markOf(String name) => find.descendant(