[client] Scroll folder list on keyboard nav

This commit is contained in:
Abhishek Shroff
2025-07-01 11:46:26 +05:30
parent 3bfd01cd83
commit 27ed35c99c
2 changed files with 58 additions and 23 deletions
@@ -151,7 +151,7 @@ class ExplorerController extends StateNotifier<ExplorerState> {
return true;
}
void updateSelection(int Function(int)? indexFn, SelectionMode mode, bool highlight) {
int updateSelection(int Function(int)? indexFn, SelectionMode mode, bool highlight) {
Set<String>? selectedIds;
int index = indexFn?.call(state.focusIndex) ?? state.focusIndex;
index = min(state.resources.length - 1, max(0, index));
@@ -196,6 +196,7 @@ class ExplorerController extends StateNotifier<ExplorerState> {
focusIndex: index,
showFocus: highlight,
);
return index;
}
Future refresh() {
+56 -22
View File
@@ -16,51 +16,85 @@ class FolderListView extends StatefulWidget {
}
class _FolderListViewState extends State<FolderListView> {
double? _rowHeight;
double _viewportHeight = 0.0;
final _scrollController = ScrollController(debugLabel: "FolderList");
@override
void initState() {
super.initState();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void ensureVisible(int index) {
final currentOffset = _scrollController.offset;
final itemStart = index * _rowHeight!;
if (itemStart < currentOffset) {
_scrollController.jumpTo(itemStart);
} else if (currentOffset <= itemStart + _rowHeight! + -_viewportHeight) {
_scrollController.jumpTo(itemStart - _viewportHeight + _rowHeight!);
}
}
@override
Widget build(BuildContext context) {
final resources = context.select<ExplorerState, List<Resource>>((state) => state.resources);
return Actions(
actions: {
FocusUpIntent: CallbackAction<FocusUpIntent>(onInvoke: (i) {
context.read<ExplorerController>().updateSelection((i) => i - 1, i.mode, true);
final index = context.read<ExplorerController>().updateSelection((i) => i - 1, i.mode, true);
ensureVisible(index);
return null;
}),
FocusDownIntent: CallbackAction<FocusDownIntent>(onInvoke: (i) {
context.read<ExplorerController>().updateSelection((i) => i + 1, i.mode, true);
final index = context.read<ExplorerController>().updateSelection((i) => i + 1, i.mode, true);
ensureVisible(index);
return null;
}),
FocusFirstIntent: CallbackAction<FocusFirstIntent>(onInvoke: (i) {
context.read<ExplorerController>().updateSelection((i) => 0, i.mode, true);
final index = context.read<ExplorerController>().updateSelection((i) => 0, i.mode, true);
ensureVisible(index);
return null;
}),
FocusLastIntent: CallbackAction<FocusLastIntent>(onInvoke: (i) {
context.read<ExplorerController>().updateSelection((i) => 4294967296, i.mode, true);
final index = context.read<ExplorerController>().updateSelection((i) => 4294967296, i.mode, true);
ensureVisible(index);
return null;
}),
},
child: Focus(
autofocus: true,
descendantsAreFocusable: false,
child: ListView.builder(
itemCount: resources.length,
itemExtent: calculateRowHeight(context),
itemBuilder: (context, index) {
final resource = resources[index];
return (resource.dir)
? ResourceDragTarget(
resourceId: resource.id,
buildItem: (context, dropTargetActive) => ResourceItemGestureHandler(
child: LayoutBuilder(builder: (context, constraints) {
_rowHeight ??= calculateRowHeight(context);
_viewportHeight = constraints.maxHeight;
return ListView.builder(
itemCount: resources.length,
itemExtent: _rowHeight,
controller: _scrollController,
itemBuilder: (context, index) {
final resource = resources[index];
return (resource.dir)
? ResourceDragTarget(
resourceId: resource.id,
buildItem: (context, dropTargetActive) => ResourceItemGestureHandler(
index: index,
resource: resource,
dropTargetActive: dropTargetActive,
),
)
: ResourceItemGestureHandler(
index: index,
resource: resource,
dropTargetActive: dropTargetActive,
),
)
: ResourceItemGestureHandler(
index: index,
resource: resource,
dropTargetActive: false,
);
}),
dropTargetActive: false,
);
});
}),
),
);
}