feat: wrap appflowy style popover

This commit is contained in:
Vincent Chan
2022-09-14 11:36:16 +08:00
parent 286781f5cc
commit 7bde75ee2f
13 changed files with 151 additions and 183 deletions

View File

@ -1,3 +1,4 @@
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -62,10 +63,11 @@ class _DateCellState extends GridCellState<GridDateCell> {
value: _cellBloc, value: _cellBloc,
child: BlocBuilder<DateCellBloc, DateCellState>( child: BlocBuilder<DateCellBloc, DateCellState>(
builder: (context, state) { builder: (context, state) {
return Popover( return AppFlowyStylePopover(
controller: _popover, controller: _popover,
offset: const Offset(0, 20), offset: const Offset(0, 20),
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
constraints: BoxConstraints.loose(const Size(320, 500)),
child: SizedBox.expand( child: SizedBox.expand(
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,

View File

@ -64,12 +64,9 @@ class _DateCellEditor extends State<DateCellEditor> {
return Container(); return Container();
} }
return OverlayContainer( return _CellCalendarWidget(
constraints: BoxConstraints.loose(const Size(320, 500)),
child: _CellCalendarWidget(
cellContext: widget.cellController, cellContext: widget.cellController,
dateTypeOptionPB: _dateTypeOptionPB!, dateTypeOptionPB: _dateTypeOptionPB!,
),
); );
} }
} }
@ -302,10 +299,11 @@ class _DateTypeOptionButton extends StatelessWidget {
return BlocSelector<DateCalBloc, DateCalState, DateTypeOptionPB>( return BlocSelector<DateCalBloc, DateCalState, DateTypeOptionPB>(
selector: (state) => state.dateTypeOptionPB, selector: (state) => state.dateTypeOptionPB,
builder: (context, dateTypeOptionPB) { builder: (context, dateTypeOptionPB) {
return Popover( return AppFlowyStylePopover(
triggerActions: triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
offset: const Offset(20, 0), offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(140, 100)),
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(title, fontSize: 12), text: FlowyText.medium(title, fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
@ -313,12 +311,9 @@ class _DateTypeOptionButton extends StatelessWidget {
rightIcon: svgWidget("grid/more", color: theme.iconColor), rightIcon: svgWidget("grid/more", color: theme.iconColor),
), ),
popupBuilder: (BuildContext popContext) { popupBuilder: (BuildContext popContext) {
return OverlayContainer( return _CalDateTimeSetting(
constraints: BoxConstraints.loose(const Size(140, 100)),
child: _CalDateTimeSetting(
dateTypeOptionPB: dateTypeOptionPB, dateTypeOptionPB: dateTypeOptionPB,
onEvent: (event) => context.read<DateCalBloc>().add(event), onEvent: (event) => context.read<DateCalBloc>().add(event),
),
); );
}, },
); );

View File

@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:appflowy_popover/popover.dart'; import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
// ignore: unused_import // ignore: unused_import
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
@ -194,8 +194,10 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
Popover( AppFlowyStylePopover(
controller: _popover, controller: _popover,
constraints: BoxConstraints.loose(
Size(SelectOptionCellEditor.editorPanelWidth, 300)),
offset: const Offset(0, 20), offset: const Offset(0, 20),
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
// triggerActions: PopoverTriggerActionFlags.c, // triggerActions: PopoverTriggerActionFlags.c,
@ -203,10 +205,7 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.onFocus?.call(true); widget.onFocus?.call(true);
}); });
return OverlayContainer( return SizedBox(
constraints: BoxConstraints.loose(
Size(SelectOptionCellEditor.editorPanelWidth, 300)),
child: SizedBox(
width: SelectOptionCellEditor.editorPanelWidth, width: SelectOptionCellEditor.editorPanelWidth,
child: SelectOptionCellEditor( child: SelectOptionCellEditor(
cellController: widget.cellControllerBuilder.build() cellController: widget.cellControllerBuilder.build()
@ -215,7 +214,6 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
widget.onFocus?.call(false); widget.onFocus?.call(false);
}, },
), ),
),
); );
}, },
onClose: () { onClose: () {

View File

@ -251,9 +251,10 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Popover( return AppFlowyStylePopover(
controller: _popoverController, controller: _popoverController,
offset: const Offset(20, 0), offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(200, 300)),
child: SizedBox( child: SizedBox(
height: GridSize.typeOptionItemHeight, height: GridSize.typeOptionItemHeight,
child: Row( child: Row(
@ -286,9 +287,7 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return SelectOptionTypeOptionEditor(
constraints: BoxConstraints.loose(const Size(200, 300)),
child: SelectOptionTypeOptionEditor(
option: widget.option, option: widget.option,
onDeleted: () { onDeleted: () {
context context
@ -302,7 +301,6 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
}, },
key: ValueKey(widget.option key: ValueKey(widget.option
.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value. .id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
),
); );
}, },
); );

View File

@ -64,19 +64,16 @@ class FieldTypeOptionEditor extends StatelessWidget {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return SizedBox( return SizedBox(
height: GridSize.typeOptionItemHeight, height: GridSize.typeOptionItemHeight,
child: Popover( child: AppFlowyStylePopover(
constraints: BoxConstraints.loose(const Size(460, 440)),
triggerActions: triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
mutex: popoverMutex, mutex: popoverMutex,
offset: const Offset(20, 0), offset: const Offset(20, 0),
popupBuilder: (context) { popupBuilder: (context) {
final list = FieldTypeList(onSelectField: (newFieldType) { return FieldTypeList(onSelectField: (newFieldType) {
dataController.switchToField(newFieldType); dataController.switchToField(newFieldType);
}); });
return OverlayContainer(
constraints: BoxConstraints.loose(const Size(460, 440)),
child: list,
);
}, },
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(field.fieldType.title(), fontSize: 12), text: FlowyText.medium(field.fieldType.title(), fontSize: 12),

View File

@ -7,6 +7,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy_popover/popover.dart'; import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
@ -176,9 +177,10 @@ class CreateFieldButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Popover( return AppFlowyStylePopover(
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
direction: PopoverDirection.bottomWithRightAligned, direction: PopoverDirection.bottomWithRightAligned,
constraints: BoxConstraints.loose(const Size(240, 200)),
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium( text: FlowyText.medium(
LocaleKeys.grid_field_newColumn.tr(), LocaleKeys.grid_field_newColumn.tr(),
@ -189,13 +191,10 @@ class CreateFieldButton extends StatelessWidget {
leftIcon: svgWidget("home/add"), leftIcon: svgWidget("home/add"),
), ),
popupBuilder: (BuildContext popover) { popupBuilder: (BuildContext popover) {
return OverlayContainer( return FieldEditor(
constraints: BoxConstraints.loose(const Size(240, 200)),
child: FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: "", fieldName: "",
typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId), typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
),
); );
}, },
); );

View File

@ -62,15 +62,14 @@ class DateTypeOptionWidget extends TypeOptionWidget {
} }
Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) { Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) {
return Popover( return AppFlowyStylePopover(
mutex: popoverMutex, mutex: popoverMutex,
triggerActions: triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
offset: const Offset(20, 0), offset: const Offset(20, 0),
popupBuilder: (popoverContext) {
return OverlayContainer(
constraints: BoxConstraints.loose(const Size(460, 440)), constraints: BoxConstraints.loose(const Size(460, 440)),
child: DateFormatList( popupBuilder: (popoverContext) {
return DateFormatList(
selectedFormat: dataFormat, selectedFormat: dataFormat,
onSelected: (format) { onSelected: (format) {
context context
@ -78,7 +77,6 @@ class DateTypeOptionWidget extends TypeOptionWidget {
.add(DateTypeOptionEvent.didSelectDateFormat(format)); .add(DateTypeOptionEvent.didSelectDateFormat(format));
PopoverContainer.of(popoverContext).closeAll(); PopoverContainer.of(popoverContext).closeAll();
}, },
),
); );
}, },
child: const DateFormatButton(), child: const DateFormatButton(),
@ -86,22 +84,21 @@ class DateTypeOptionWidget extends TypeOptionWidget {
} }
Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) { Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) {
return Popover( return AppFlowyStylePopover(
mutex: popoverMutex, mutex: popoverMutex,
triggerActions: triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click, PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
offset: const Offset(20, 0), offset: const Offset(20, 0),
popupBuilder: (BuildContext popoverContext) {
return OverlayContainer(
constraints: BoxConstraints.loose(const Size(460, 440)), constraints: BoxConstraints.loose(const Size(460, 440)),
child: TimeFormatList( popupBuilder: (BuildContext popoverContext) {
return TimeFormatList(
selectedFormat: timeFormat, selectedFormat: timeFormat,
onSelected: (format) { onSelected: (format) {
context context
.read<DateTypeOptionBloc>() .read<DateTypeOptionBloc>()
.add(DateTypeOptionEvent.didSelectTimeFormat(format)); .add(DateTypeOptionEvent.didSelectTimeFormat(format));
PopoverContainer.of(popoverContext).closeAll(); PopoverContainer.of(popoverContext).closeAll();
}), },
); );
}, },
child: TimeFormatButton(timeFormat: timeFormat), child: TimeFormatButton(timeFormat: timeFormat),

View File

@ -55,11 +55,12 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
listener: (context, state) => listener: (context, state) =>
typeOptionContext.typeOption = state.typeOption, typeOptionContext.typeOption = state.typeOption,
builder: (context, state) { builder: (context, state) {
return Popover( return AppFlowyStylePopover(
mutex: popoverMutex, mutex: popoverMutex,
triggerActions: PopoverTriggerActionFlags.hover | triggerActions: PopoverTriggerActionFlags.hover |
PopoverTriggerActionFlags.click, PopoverTriggerActionFlags.click,
offset: const Offset(20, 0), offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(460, 440)),
child: FlowyButton( child: FlowyButton(
margin: GridSize.typeOptionContentInsets, margin: GridSize.typeOptionContentInsets,
hoverColor: theme.hover, hoverColor: theme.hover,
@ -76,9 +77,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return NumberFormatList(
constraints: BoxConstraints.loose(const Size(460, 440)),
child: NumberFormatList(
onSelected: (format) { onSelected: (format) {
context context
.read<NumberTypeOptionBloc>() .read<NumberTypeOptionBloc>()
@ -86,7 +85,6 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
PopoverContainer.of(popoverContext).closeAll(); PopoverContainer.of(popoverContext).closeAll();
}, },
selectedFormat: state.typeOption.format, selectedFormat: state.typeOption.format,
),
); );
}, },
); );

View File

@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/select_opti
import 'package:appflowy_popover/popover.dart'; import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
@ -180,10 +181,11 @@ class _OptionCellState extends State<_OptionCell> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Popover( return AppFlowyStylePopover(
controller: _popoverController, controller: _popoverController,
mutex: widget.popoverMutex, mutex: widget.popoverMutex,
offset: const Offset(20, 0), offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(460, 440)),
child: SizedBox( child: SizedBox(
height: GridSize.typeOptionItemHeight, height: GridSize.typeOptionItemHeight,
child: SelectOptionTagCell( child: SelectOptionTagCell(
@ -200,9 +202,7 @@ class _OptionCellState extends State<_OptionCell> {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return SelectOptionTypeOptionEditor(
constraints: BoxConstraints.loose(const Size(460, 440)),
child: SelectOptionTypeOptionEditor(
option: widget.option, option: widget.option,
onDeleted: () { onDeleted: () {
context context
@ -217,7 +217,6 @@ class _OptionCellState extends State<_OptionCell> {
PopoverContainer.of(popoverContext).closeAll(); PopoverContainer.of(popoverContext).closeAll();
}, },
key: ValueKey(widget.option.id), key: ValueKey(widget.option.id),
),
); );
}, },
); );

View File

@ -116,10 +116,11 @@ class _GridPropertyCell extends StatelessWidget {
} }
Widget _editFieldButton(AppTheme theme, BuildContext context) { Widget _editFieldButton(AppTheme theme, BuildContext context) {
return Popover( return AppFlowyStylePopover(
mutex: popoverMutex, mutex: popoverMutex,
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
offset: const Offset(20, 0), offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(240, 200)),
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(fieldContext.name, fontSize: 12), text: FlowyText.medium(fieldContext.name, fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
@ -127,14 +128,11 @@ class _GridPropertyCell extends StatelessWidget {
color: theme.iconColor), color: theme.iconColor),
), ),
popupBuilder: (BuildContext context) { popupBuilder: (BuildContext context) {
return OverlayContainer( return FieldEditor(
constraints: BoxConstraints.loose(const Size(240, 200)),
child: FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: fieldContext.name, fieldName: fieldContext.name,
typeOptionLoader: FieldTypeOptionLoader( typeOptionLoader:
gridId: gridId, field: fieldContext.field), FieldTypeOptionLoader(gridId: gridId, field: fieldContext.field),
),
); );
}, },
); );

View File

@ -9,4 +9,4 @@ export 'src/flowy_overlay/flowy_overlay.dart';
export 'src/flowy_overlay/list_overlay.dart'; export 'src/flowy_overlay/list_overlay.dart';
export 'src/flowy_overlay/option_overlay.dart'; export 'src/flowy_overlay/option_overlay.dart';
export 'src/flowy_overlay/flowy_dialog.dart'; export 'src/flowy_overlay/flowy_dialog.dart';
export 'src/flowy_overlay/flowy_popover.dart'; export 'src/flowy_overlay/appflowy_stype_popover.dart';

View File

@ -0,0 +1,46 @@
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:flutter/material.dart';
class AppFlowyStylePopover extends StatelessWidget {
final Widget child;
final PopoverController? controller;
final Widget Function(BuildContext context) popupBuilder;
final PopoverDirection direction;
final int triggerActions;
final BoxConstraints? constraints;
final void Function()? onClose;
final PopoverMutex? mutex;
final Offset? offset;
const AppFlowyStylePopover({
Key? key,
required this.child,
required this.popupBuilder,
this.direction = PopoverDirection.rightWithTopAligned,
this.onClose,
this.constraints,
this.mutex,
this.triggerActions = 0,
this.offset,
this.controller,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Popover(
controller: controller,
onClose: onClose,
direction: direction,
mutex: mutex,
triggerActions: triggerActions,
popupBuilder: (context) {
return OverlayContainer(
constraints: constraints,
child: popupBuilder(context),
);
},
child: child,
);
}
}

View File

@ -1,59 +0,0 @@
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 './flowy_popover_layout.dart';
const _overlayContainerPadding = EdgeInsets.all(12);
class FlowyPopover extends StatefulWidget {
final Widget Function(BuildContext context) builder;
final ShapeBorder? shape;
final Rect anchorRect;
final AnchorDirection? anchorDirection;
final EdgeInsets padding;
final BoxConstraints? constraints;
const FlowyPopover({
Key? key,
required this.builder,
required this.anchorRect,
this.shape,
this.padding = _overlayContainerPadding,
this.anchorDirection,
this.constraints,
}) : super(key: key);
@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: widget.anchorRect,
anchorDirection:
widget.anchorDirection ?? AnchorDirection.rightWithTopAligned,
overlapBehaviour: OverlapBehaviour.stretch,
),
child: Container(
padding: widget.padding,
constraints: widget.constraints ??
BoxConstraints.loose(const Size(280, 400)),
decoration: FlowyDecoration.decoration(
theme.surface, theme.shadowColor.withOpacity(0.15)),
key: preRenderKey,
child: widget.builder(context),
)));
}
}