Files
plezy/lib/utils/focus_utils.dart
edde746 4712414b3d fix(focus): reclaim detached grid nodes without stealing live focus
Historical focus contexts kept detached grid nodes alive, while stale menu captures could queue focus after their row was gone.

Track actual attachment lifetime, preserve pending and remembered destinations, and restore captured focus only to a live eligible leaf without overriding a covering route.
2026-09-06 20:21:11 +02:00

36 lines
1.3 KiB
Dart

import 'package:flutter/widgets.dart';
class FocusUtils {
FocusUtils._();
/// Request focus on a FocusNode after the current frame completes.
/// Safely checks if the State is still mounted before requesting focus.
///
/// Usage:
/// ```dart
/// FocusUtils.requestFocusAfterBuild(this, _focusNode);
/// ```
static void requestFocusAfterBuild(State state, FocusNode focusNode) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (state.mounted) {
focusNode.requestFocus();
}
});
}
/// Restore a captured menu destination only while its owner and live leaf
/// still allow it. Unlike initial focus, this must not queue a detached node.
static void restoreFocusAfterBuild(State state, FocusNode focusNode) {
// A post-frame callback may not run until this node is attached again.
// Do not let an already-detached capture become a future focus request.
if (focusNode.parent == null || !focusNode.canRequestFocus) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!state.mounted) return;
final destination = focusNode.context;
if (destination == null || !destination.mounted || focusNode.parent == null || !focusNode.canRequestFocus) return;
if (!(ModalRoute.of(state.context)?.isCurrent ?? true)) return;
focusNode.requestFocus();
});
}
}