mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add popover overlay
This commit is contained in:
@ -114,16 +114,14 @@ class FieldEditorPopOver extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowyPopover(
|
return FlowyPopover(
|
||||||
child: Container(
|
builder: (BuildContext context) {
|
||||||
constraints: BoxConstraints.loose(const Size(280, 400)),
|
return FieldEditor(
|
||||||
width: 280,
|
|
||||||
height: 400,
|
|
||||||
child: FieldEditor(
|
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
fieldName: fieldName,
|
fieldName: fieldName,
|
||||||
typeOptionLoader: typeOptionLoader,
|
typeOptionLoader: typeOptionLoader,
|
||||||
key: key),
|
key: key);
|
||||||
));
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static show(
|
static show(
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
|
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/decoration.dart';
|
||||||
|
import 'package:flowy_infra/theme.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import './flowy_popover_layout.dart';
|
||||||
|
|
||||||
const _overlayContainerPadding = EdgeInsets.all(12);
|
const _overlayContainerPadding = EdgeInsets.all(12);
|
||||||
|
|
||||||
class FlowyPopover extends StatelessWidget {
|
class FlowyPopover extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget Function(BuildContext context) builder;
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder? shape;
|
||||||
|
final EdgeInsets padding;
|
||||||
|
|
||||||
FlowyPopover({Key? key, required this.child, this.shape}) : super(key: key);
|
FlowyPopover({
|
||||||
|
Key? key,
|
||||||
@override
|
required this.builder,
|
||||||
Widget build(BuildContext context) {
|
this.shape,
|
||||||
return SimpleDialog(
|
this.padding = _overlayContainerPadding,
|
||||||
shape: shape ??
|
}) : super(key: key);
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
||||||
children: [Container(padding: _overlayContainerPadding, child: child)],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static show(
|
static show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
@ -24,4 +26,34 @@ class FlowyPopover extends StatelessWidget {
|
|||||||
showDialog(
|
showDialog(
|
||||||
barrierColor: Colors.transparent, context: context, builder: builder);
|
barrierColor: Colors.transparent, context: context, builder: builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FlowyPopover> createState() => _FlowyPopoverState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FlowyPopoverState extends State<FlowyPopover> {
|
||||||
|
final preRenderKey = GlobalKey();
|
||||||
|
Size? size;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme =
|
||||||
|
context.watch<AppTheme?>() ?? AppTheme.fromType(ThemeType.light);
|
||||||
|
return Material(
|
||||||
|
type: MaterialType.transparency,
|
||||||
|
child: CustomSingleChildLayout(
|
||||||
|
delegate: PopoverLayoutDelegate(
|
||||||
|
anchorRect: const Rect.fromLTWH(0, 0, 280, 400),
|
||||||
|
anchorDirection: AnchorDirection.rightWithTopAligned,
|
||||||
|
overlapBehaviour: OverlapBehaviour.stretch,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
padding: widget.padding,
|
||||||
|
constraints: BoxConstraints.loose(const Size(280, 400)),
|
||||||
|
decoration: FlowyDecoration.decoration(
|
||||||
|
theme.surface, theme.shadowColor.withOpacity(0.15)),
|
||||||
|
key: preRenderKey,
|
||||||
|
child: widget.builder(context),
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,251 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'flowy_overlay.dart';
|
||||||
|
|
||||||
|
class PopoverLayoutDelegate extends SingleChildLayoutDelegate {
|
||||||
|
PopoverLayoutDelegate({
|
||||||
|
required this.anchorRect,
|
||||||
|
required this.anchorDirection,
|
||||||
|
required this.overlapBehaviour,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Rect anchorRect;
|
||||||
|
final AnchorDirection anchorDirection;
|
||||||
|
final OverlapBehaviour overlapBehaviour;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRelayout(PopoverLayoutDelegate oldDelegate) {
|
||||||
|
return anchorRect != oldDelegate.anchorRect ||
|
||||||
|
anchorDirection != oldDelegate.anchorDirection ||
|
||||||
|
overlapBehaviour != oldDelegate.overlapBehaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
|
||||||
|
switch (overlapBehaviour) {
|
||||||
|
case OverlapBehaviour.none:
|
||||||
|
return constraints.loosen();
|
||||||
|
case OverlapBehaviour.stretch:
|
||||||
|
BoxConstraints childConstraints;
|
||||||
|
switch (anchorDirection) {
|
||||||
|
case AnchorDirection.topLeft:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topRight:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.right,
|
||||||
|
anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomLeft:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
constraints.maxHeight - anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomRight:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.right,
|
||||||
|
constraints.maxHeight - anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.center:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth,
|
||||||
|
constraints.maxHeight,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithLeftAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.left,
|
||||||
|
anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithCenterAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth,
|
||||||
|
anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithRightAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.right,
|
||||||
|
anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithTopAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.right,
|
||||||
|
constraints.maxHeight - anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithCenterAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.right,
|
||||||
|
constraints.maxHeight,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithBottomAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth - anchorRect.right,
|
||||||
|
anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithLeftAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
constraints.maxHeight - anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithCenterAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
constraints.maxWidth,
|
||||||
|
constraints.maxHeight - anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithRightAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.right,
|
||||||
|
constraints.maxHeight - anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithTopAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
constraints.maxHeight - anchorRect.top,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithCenterAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
constraints.maxHeight,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithBottomAligned:
|
||||||
|
childConstraints = BoxConstraints.loose(Size(
|
||||||
|
anchorRect.left,
|
||||||
|
anchorRect.bottom,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case AnchorDirection.custom:
|
||||||
|
childConstraints = constraints.loosen();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
return childConstraints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Offset getPositionForChild(Size size, Size childSize) {
|
||||||
|
Offset position;
|
||||||
|
switch (anchorDirection) {
|
||||||
|
case AnchorDirection.topLeft:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left - childSize.width,
|
||||||
|
anchorRect.top - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topRight:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right,
|
||||||
|
anchorRect.top - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomLeft:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left - childSize.width,
|
||||||
|
anchorRect.bottom,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomRight:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right,
|
||||||
|
anchorRect.bottom,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.center:
|
||||||
|
position = anchorRect.center;
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithLeftAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left,
|
||||||
|
anchorRect.top - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithCenterAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,
|
||||||
|
anchorRect.top - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.topWithRightAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right - childSize.width,
|
||||||
|
anchorRect.top - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithTopAligned:
|
||||||
|
position = Offset(anchorRect.right, anchorRect.top);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithCenterAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right,
|
||||||
|
anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.rightWithBottomAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right,
|
||||||
|
anchorRect.bottom - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithLeftAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left,
|
||||||
|
anchorRect.bottom,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithCenterAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,
|
||||||
|
anchorRect.bottom,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.bottomWithRightAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.right - childSize.width,
|
||||||
|
anchorRect.bottom,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithTopAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left - childSize.width,
|
||||||
|
anchorRect.top,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithCenterAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left - childSize.width,
|
||||||
|
anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AnchorDirection.leftWithBottomAligned:
|
||||||
|
position = Offset(
|
||||||
|
anchorRect.left - childSize.width,
|
||||||
|
anchorRect.bottom - childSize.height,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
return Offset(
|
||||||
|
math.max(0.0, math.min(size.width - childSize.width, position.dx)),
|
||||||
|
math.max(0.0, math.min(size.height - childSize.height, position.dy)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user