78 lines
2.4 KiB
Dart
78 lines
2.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../focus/input_mode_tracker.dart';
|
|
import '../focus/dpad_navigator.dart';
|
|
import '../focus/key_event_utils.dart';
|
|
|
|
/// A wrapper widget that provides autofocus functionality for bottom sheets.
|
|
///
|
|
/// When the sheet opens and keyboard/controller mode is active, this widget
|
|
/// will automatically request focus on the provided [initialFocusNode].
|
|
/// This enables keyboard/controller navigation within the sheet.
|
|
///
|
|
/// When opened via touch/mouse, no autofocus occurs to avoid showing
|
|
/// focus indicators unnecessarily.
|
|
class FocusableBottomSheet extends StatefulWidget {
|
|
/// The content of the bottom sheet.
|
|
final Widget child;
|
|
|
|
/// The FocusNode to focus when the sheet opens in keyboard mode.
|
|
/// If null, no autofocus occurs.
|
|
final FocusNode? initialFocusNode;
|
|
|
|
const FocusableBottomSheet({super.key, required this.child, this.initialFocusNode});
|
|
|
|
@override
|
|
State<FocusableBottomSheet> createState() => _FocusableBottomSheetState();
|
|
}
|
|
|
|
class _FocusableBottomSheetState extends State<FocusableBottomSheet> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// Clear any stale back key suppression from previous sheet closes
|
|
BackKeyUpSuppressor.clearSuppression();
|
|
_requestInitialFocus();
|
|
}
|
|
|
|
void _requestInitialFocus() {
|
|
if (widget.initialFocusNode == null) return;
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (!mounted) return;
|
|
|
|
// Only autofocus when in keyboard/controller mode
|
|
if (InputModeTracker.isKeyboardMode(context)) {
|
|
widget.initialFocusNode?.requestFocus();
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(FocusableBottomSheet oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
// If the focus node changed, request focus on the new one
|
|
if (widget.initialFocusNode != oldWidget.initialFocusNode) {
|
|
_requestInitialFocus();
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Focus(
|
|
canRequestFocus: false,
|
|
skipTraversal: true,
|
|
onKeyEvent: (node, event) {
|
|
// Handle select key suppression (for when sheet was opened via select key)
|
|
if (SelectKeyUpSuppressor.consumeIfSuppressed(event)) {
|
|
return KeyEventResult.handled;
|
|
}
|
|
// Handle back key to close the bottom sheet
|
|
return handleBackKeyNavigation(context, event);
|
|
},
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|