[infra_ui][overlay] (WIP) Impl new overlay lifecycle actions

This commit is contained in:
Jaylen Bian 2021-07-26 12:52:08 +08:00
parent 7efbf03030
commit 440d2940c3

View File

@ -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;
}
}