76 lines
2.3 KiB
Dart
76 lines
2.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'focus_theme.dart';
|
|
import 'focusable_wrapper.dart';
|
|
import 'input_mode_tracker.dart';
|
|
|
|
class FocusableButton extends StatefulWidget {
|
|
final Widget child;
|
|
final VoidCallback? onPressed;
|
|
final bool autofocus;
|
|
final FocusNode? focusNode;
|
|
|
|
/// Navigation callbacks for explicit focus control (e.g. horizontal button rows).
|
|
final VoidCallback? onNavigateUp;
|
|
final VoidCallback? onNavigateDown;
|
|
final VoidCallback? onNavigateLeft;
|
|
final VoidCallback? onNavigateRight;
|
|
final VoidCallback? onBack;
|
|
|
|
/// Whether to scroll the widget into view when focused.
|
|
final bool autoScroll;
|
|
|
|
/// Whether to use background color instead of border for focus indicator.
|
|
final bool useBackgroundFocus;
|
|
|
|
const FocusableButton({
|
|
super.key,
|
|
required this.child,
|
|
this.onPressed,
|
|
this.autofocus = false,
|
|
this.focusNode,
|
|
this.onNavigateUp,
|
|
this.onNavigateDown,
|
|
this.onNavigateLeft,
|
|
this.onNavigateRight,
|
|
this.onBack,
|
|
this.autoScroll = true,
|
|
this.useBackgroundFocus = false,
|
|
});
|
|
|
|
@override
|
|
State<FocusableButton> createState() => _FocusableButtonState();
|
|
}
|
|
|
|
class _FocusableButtonState extends State<FocusableButton> {
|
|
bool _isFocused = false;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isKeyboard = InputModeTracker.isKeyboardMode(context);
|
|
final showFocus = _isFocused && isKeyboard;
|
|
final duration = FocusTheme.getAnimationDuration(context);
|
|
final enabled = widget.onPressed != null;
|
|
final opacity = isKeyboard && !_isFocused ? 0.6 : 1.0;
|
|
|
|
return FocusableWrapper(
|
|
autofocus: widget.autofocus && enabled,
|
|
focusNode: widget.focusNode,
|
|
canRequestFocus: enabled,
|
|
disableScale: true,
|
|
borderRadius: 100,
|
|
useBackgroundFocus: widget.useBackgroundFocus,
|
|
descendantsAreFocusable: false,
|
|
onFocusChange: (f) => setState(() => _isFocused = f),
|
|
autoScroll: widget.autoScroll,
|
|
onSelect: widget.onPressed,
|
|
onNavigateUp: widget.onNavigateUp,
|
|
onNavigateDown: widget.onNavigateDown,
|
|
onNavigateLeft: widget.onNavigateLeft,
|
|
onNavigateRight: widget.onNavigateRight,
|
|
onBack: widget.onBack,
|
|
child: AnimatedOpacity(opacity: showFocus ? 1.0 : opacity, duration: duration, child: widget.child),
|
|
);
|
|
}
|
|
}
|