fix: bounds-safe action bar focus node access

This commit is contained in:
edde746
2026-04-13 22:00:36 +02:00
parent b81f6eaa96
commit 2126a38f39
5 changed files with 14 additions and 13 deletions
+6 -2
View File
@@ -88,8 +88,12 @@ class FocusableActionBarState extends State<FocusableActionBar> {
late List<FocusNode> _focusNodes;
late List<bool> _focusStates;
/// Access a focus node by index (e.g. for external `requestFocus()` calls).
FocusNode getFocusNode(int index) => _focusNodes[index];
FocusNode? getFocusNode(int index) =>
index >= 0 && index < _focusNodes.length ? _focusNodes[index] : null;
void requestFocusOnFirst() {
if (_focusNodes.isNotEmpty) _focusNodes.first.requestFocus();
}
@override
void initState() {
+3 -3
View File
@@ -188,7 +188,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
if (_isHeroSectionVisible) {
_heroFocusNode.requestFocus();
} else {
_actionBarKey.currentState?.getFocusNode(0).requestFocus();
_actionBarKey.currentState?.requestFocusOnFirst();
}
_scrollToTop();
}
@@ -275,7 +275,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
final keys = _allHubKeys;
if (keys.isNotEmpty) keys.first.currentState?.requestFocusFromMemory();
},
onUp: () => _actionBarKey.currentState?.getFocusNode(0).requestFocus(),
onUp: () => _actionBarKey.currentState?.requestFocusOnFirst(),
onLeft: () {
if (_currentHeroIndex > 0) {
_heroController.previousPage(duration: tokens(context).slow, curve: Curves.easeInOut);
@@ -824,7 +824,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
final actionBar = _actionBarKey.currentState;
if (actionBar == null) return;
final lastNode = actionBar.getFocusNode(actionBar.widget.actions.length - 1);
final RenderBox? button = lastNode.context?.findRenderObject() as RenderBox?;
final RenderBox? button = lastNode?.context?.findRenderObject() as RenderBox?;
if (button == null) return;
final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject() as RenderBox;
@@ -47,10 +47,7 @@ mixin FocusableDetailScreenMixin<T extends StatefulWidget> on State<T>, GridFocu
setState(() {
isAppBarFocused = true;
});
final state = actionBarKey.currentState;
if (state != null && getAppBarActions().isNotEmpty) {
state.getFocusNode(0).requestFocus();
}
actionBarKey.currentState?.requestFocusOnFirst();
// Scroll to top to show the app bar
scrollController.animateTo(0, duration: const Duration(milliseconds: 200), curve: Curves.easeOut);
}
+2 -2
View File
@@ -821,7 +821,7 @@ class _LibrariesScreenState extends State<LibrariesScreen>
i,
onSelectWhenActive: _focusCurrentTab,
onNavigateDown: _focusCurrentTabFromTabBar,
onNavigateRightFromLast: () => _actionBarKey.currentState?.getFocusNode(0).requestFocus(),
onNavigateRightFromLast: () => _actionBarKey.currentState?.requestFocusOnFirst(),
),
],
],
@@ -965,7 +965,7 @@ class _LibrariesScreenState extends State<LibrariesScreen>
i,
onSelectWhenActive: _focusCurrentTab,
onNavigateDown: _focusCurrentTabFromTabBar,
onNavigateRightFromLast: () => _actionBarKey.currentState?.getFocusNode(0).requestFocus(),
onNavigateRightFromLast: () => _actionBarKey.currentState?.requestFocusOnFirst(),
),
],
],
+2 -2
View File
@@ -339,7 +339,7 @@ class _LiveTvScreenState extends State<LiveTvScreen>
i,
onSelectWhenActive: _focusCurrentTab,
onNavigateDown: _focusCurrentTab,
onNavigateRightFromLast: () => _actionBarKey.currentState?.getFocusNode(0).requestFocus(),
onNavigateRightFromLast: () => _actionBarKey.currentState?.requestFocusOnFirst(),
),
],
],
@@ -421,7 +421,7 @@ class _LiveTvScreenState extends State<LiveTvScreen>
i,
onSelectWhenActive: _focusCurrentTab,
onNavigateDown: _focusCurrentTab,
onNavigateRightFromLast: () => _actionBarKey.currentState?.getFocusNode(0).requestFocus(),
onNavigateRightFromLast: () => _actionBarKey.currentState?.requestFocusOnFirst(),
),
],
],