WIP 76 보충: 목록 줄에 항목 경로 키 - 줄 목록이 바뀔 때 누른 줄의 두 번 누르기 기다림이 다른 항목으로 넘어가지 않게 (setState during build) (검토 대기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음6
parent
1eef4ff65f
commit
320025c5fa
|
|
@ -3139,7 +3139,9 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
controller: pane.scroll,
|
||||
itemCount: rows.length,
|
||||
itemExtent: look.rowHeightOf(context),
|
||||
itemBuilder: (_, k) => _rowView(pane, rows[k], compact: foldersOnly),
|
||||
// 76: 줄 위젯은 항목을 따라간다 (아래 [_rowKey])
|
||||
itemBuilder: (_, k) => KeyedSubtree(key: _rowKey(rows[k]), child: _rowView(pane, rows[k], compact: foldersOnly)),
|
||||
findChildIndexCallback: _rowIndexOf(rows),
|
||||
),
|
||||
// 읽는 중 (WebDAV 서버를 기다릴 때 등). 180: 목록 위에 겹쳐 그린다 (끼어들면 목록이 밀려 다음 것을 누르려다 엉뚱한 것을 누른다)
|
||||
if (pane.loading.isNotEmpty) const Positioned(left: 0, right: 0, top: 0, child: LinearProgressIndicator(minHeight: 2)),
|
||||
|
|
@ -3149,6 +3151,17 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
]));
|
||||
}
|
||||
|
||||
/// 76: 목록 줄의 키 = 항목 경로. 키가 없으면 줄 목록이 바뀔 때 (빠른 필터 · 펼치기 · 새로 고침) 같은 자리의 줄 위젯을
|
||||
/// 다른 항목에 다시 써서, 방금 누른 파일 줄이 폴더 줄로 바뀌면 두 번 누르기 기다림이 그리는 중에 버려지고
|
||||
/// 그 누르기가 다른 항목에 들어갔다 (디버그에서는 "setState() called during build")
|
||||
static Key _rowKey(_Row r) => ValueKey<String>('${r.isRoot ? 'root:' : r.isUp ? 'up:' : ''}${r.entry.path}');
|
||||
|
||||
/// 76: 줄이 옮겨 가도 같은 줄 위젯을 찾게 (키 → 지금 자리)
|
||||
static int? Function(Key) _rowIndexOf(List<_Row> rows) {
|
||||
Map<Key, int>? index;
|
||||
return (key) => (index ??= {for (var i = 0; i < rows.length; i++) _rowKey(rows[i]): i})[key];
|
||||
}
|
||||
|
||||
/// "폴더 + 파일 목록" 배치의 오른쪽: 왼쪽 트리에서 고른 폴더의 내용 (맨 위 ".." = 상위 폴더)
|
||||
Widget _listView(_Pane pane) {
|
||||
final dir = pane.current;
|
||||
|
|
@ -3182,7 +3195,8 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
controller: pane.listScroll,
|
||||
itemCount: rows.length,
|
||||
itemExtent: look.rowHeightOf(context),
|
||||
itemBuilder: (_, k) => _rowView(pane, rows[k], list: true),
|
||||
itemBuilder: (_, k) => KeyedSubtree(key: _rowKey(rows[k]), child: _rowView(pane, rows[k], list: true)),
|
||||
findChildIndexCallback: _rowIndexOf(rows),
|
||||
),
|
||||
),
|
||||
if (_selecting) _marksBar(pane, listDir: dir),
|
||||
|
|
|
|||
|
|
@ -569,8 +569,11 @@ void main() {
|
|||
expect(find.textContaining('이름에 든 글자로 좁히기'), findsNothing);
|
||||
expect(names(), containsAll(['doc.txt', 'sub', 'ep01.mkv', 'other.txt']));
|
||||
|
||||
// 닫으면 키는 탐색기로 돌아온다 - 목록에서 글자를 바로 치면 그 글자로 열린다
|
||||
// 닫으면 키는 탐색기로 돌아온다 - 목록에서 글자를 바로 치면 그 글자로 열린다.
|
||||
// 사람처럼 줄을 누르고 곧바로 친다 (두 번 누르기를 기다리는 중에 줄 목록이 바뀜)
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('doc.txt').first);
|
||||
await tester.pump(const Duration(milliseconds: 20));
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.keyO, character: 'o');
|
||||
await calm(tester);
|
||||
expect(tester.widget<TextField>(find.byType(TextField).first).controller!.text, 'o');
|
||||
|
|
@ -579,6 +582,32 @@ void main() {
|
|||
await tester.enterText(find.byType(TextField).first, 'oth');
|
||||
await tester.pump();
|
||||
expect(names(), ['other.txt']);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('76: 파일 줄을 누르고 곧바로 쳐서 그 줄이 사라지거나 다른 줄이 그 자리에 와도, 누른 것이 다른 항목에 들어가지 않는다', (tester) async {
|
||||
for (final n in ['a1.mkv', 'b2.mkv']) {
|
||||
File(p.join(left, n)).writeAsStringSync('x');
|
||||
}
|
||||
Directory(p.join(left, 'a_folder')).createSync();
|
||||
await open(tester);
|
||||
await settle(tester, () => find.text('b2.mkv').evaluate().isNotEmpty);
|
||||
// 누르기 = 선택 (두 번 = 실행) 모드: 파일 줄은 두 번 누르기를 기다린다
|
||||
await tester.tap(find.text('b2.mkv').first);
|
||||
await tester.pump(const Duration(milliseconds: 20));
|
||||
// "a" → b2.mkv 가 사라지고 그 자리에 폴더 · 다른 파일이 온다
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.keyA, character: 'a');
|
||||
await tester.pump();
|
||||
expect(tester.takeException(), isNull);
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(tester.takeException(), isNull);
|
||||
expect(find.text('b2.mkv'), findsNothing);
|
||||
expect(shell.opened, isEmpty, reason: '누른 것이 실행되지 않음');
|
||||
// 다른 항목이 고른 것 (강조) 이 되지 않음 - 폴더가 펼쳐지지도 않음
|
||||
expect(find.text('a_folder'), findsOneWidget);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||
await calm(tester);
|
||||
expect(find.text('b2.mkv'), findsOneWidget);
|
||||
});
|
||||
|
||||
test('76: 빠른 필터 맞추기 - 빈 칸은 모두 · 글자는 이름 안 어디든 · * ? 는 이름 전체 패턴', () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue