|
@@ -1,37 +1,104 @@
|
|
|
+import 'dart:ui' show window;
|
|
|
+
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
import 'overlay_basis.dart';
|
|
|
import 'overlay_layout_delegate.dart';
|
|
|
|
|
|
-class OverlayPannel extends StatelessWidget {
|
|
|
+class OverlayPannel extends StatefulWidget {
|
|
|
const OverlayPannel({
|
|
|
Key? key,
|
|
|
- required this.child,
|
|
|
- required this.targetRect,
|
|
|
- required this.anchorRect,
|
|
|
- this.safeAreaEnabled = true,
|
|
|
- this.anchorDirection = AnchorDirection.topRight,
|
|
|
- this.insets = EdgeInsets.zero,
|
|
|
+ this.focusNode,
|
|
|
}) : super(key: key);
|
|
|
|
|
|
- final AnchorDirection anchorDirection;
|
|
|
- final bool safeAreaEnabled;
|
|
|
- final EdgeInsets insets;
|
|
|
- final Rect targetRect;
|
|
|
- final Rect anchorRect;
|
|
|
- final Widget child;
|
|
|
+ final FocusNode? focusNode;
|
|
|
+
|
|
|
+ @override
|
|
|
+ _OverlayPannelState createState() => _OverlayPannelState();
|
|
|
+}
|
|
|
+
|
|
|
+class _OverlayPannelState extends State<OverlayPannel> with WidgetsBindingObserver {
|
|
|
+ FocusNode? _internalNode;
|
|
|
+ FocusNode? get focusNode => widget.focusNode ?? _internalNode;
|
|
|
+ late FocusHighlightMode _focusHighlightMode;
|
|
|
+ bool _hasPrimaryFocus = false;
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ super.initState();
|
|
|
+ if (widget.focusNode == null) {
|
|
|
+ _internalNode ??= _createFocusNode();
|
|
|
+ }
|
|
|
+ focusNode!.addListener(_handleFocusChanged);
|
|
|
+ final FocusManager focusManager = WidgetsBinding.instance!.focusManager;
|
|
|
+ _focusHighlightMode = focusManager.highlightMode;
|
|
|
+ focusManager.addHighlightModeListener(_handleFocusHighlightModeChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ WidgetsBinding.instance!.removeObserver(this);
|
|
|
+ focusNode!.removeListener(_handleFocusChanged);
|
|
|
+ WidgetsBinding.instance!.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChanged);
|
|
|
+ _internalNode?.dispose();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- return CustomSingleChildLayout(
|
|
|
- delegate: OverlayLayoutDelegate(
|
|
|
- targetRect: targetRect,
|
|
|
- anchorRect: anchorRect,
|
|
|
- safeAreaEnabled: safeAreaEnabled,
|
|
|
- anchorDirection: anchorDirection,
|
|
|
- insets: insets,
|
|
|
- ),
|
|
|
- child: child,
|
|
|
- );
|
|
|
+ return Container();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void didUpdateWidget(OverlayPannel oldWidget) {
|
|
|
+ super.didUpdateWidget(oldWidget);
|
|
|
+ if (widget.focusNode != oldWidget.focusNode) {
|
|
|
+ oldWidget.focusNode?.removeListener(_handleFocusChanged);
|
|
|
+ if (widget.focusNode == null) {
|
|
|
+ _internalNode ??= _createFocusNode();
|
|
|
+ }
|
|
|
+ _hasPrimaryFocus = focusNode!.hasPrimaryFocus;
|
|
|
+ focusNode!.addListener(_handleFocusChanged);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: Focus & Route
|
|
|
+
|
|
|
+ FocusNode _createFocusNode() {
|
|
|
+ return FocusNode(debugLabel: '${widget.runtimeType}');
|
|
|
+ }
|
|
|
+
|
|
|
+ void _handleFocusChanged() {
|
|
|
+ if (_hasPrimaryFocus != focusNode!.hasPrimaryFocus) {
|
|
|
+ setState(() {
|
|
|
+ _hasPrimaryFocus = focusNode!.hasPrimaryFocus;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void _handleFocusHighlightModeChanged(FocusHighlightMode mode) {
|
|
|
+ if (!mounted) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setState(() {
|
|
|
+ _focusHighlightMode = mode;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ void _removeOverlayRoute() {
|
|
|
+ // TODO: junlin
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: Layout
|
|
|
+
|
|
|
+ Orientation _getOrientation(BuildContext context) {
|
|
|
+ Orientation? result = MediaQuery.maybeOf(context)?.orientation;
|
|
|
+ if (result == null) {
|
|
|
+ // If there's no MediaQuery, then use the window aspect to determine
|
|
|
+ // orientation.
|
|
|
+ final Size size = window.physicalSize;
|
|
|
+ result = size.width > size.height ? Orientation.landscape : Orientation.portrait;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
}
|