Merge pull request #1045 from AppFlowy-IO/feat/wrap-appflowy-style-popover

This commit is contained in:
Nathan.fooo 2022-09-15 22:34:13 +08:00 committed by GitHub
commit 4f34068f51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 291 additions and 308 deletions

View File

@ -2,11 +2,12 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/board/application/toolbar/board_setting_bloc.dart'; import 'package:app_flowy/plugins/board/application/toolbar/board_setting_bloc.dart';
import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart'; import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_group.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_property.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_property.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
@ -141,10 +142,12 @@ extension _GridSettingExtension on BoardSettingAction {
} }
class BoardSettingListPopover extends StatefulWidget { class BoardSettingListPopover extends StatefulWidget {
final PopoverController popoverController;
final BoardSettingContext settingContext; final BoardSettingContext settingContext;
const BoardSettingListPopover({ const BoardSettingListPopover({
Key? key, Key? key,
required this.popoverController,
required this.settingContext, required this.settingContext,
}) : super(key: key); }) : super(key: key);
@ -153,36 +156,33 @@ class BoardSettingListPopover extends StatefulWidget {
} }
class _BoardSettingListPopoverState extends State<BoardSettingListPopover> { class _BoardSettingListPopoverState extends State<BoardSettingListPopover> {
bool _showGridPropertyList = false; BoardSettingAction? _action;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_showGridPropertyList) { if (_action != null) {
return OverlayContainer( switch (_action!) {
constraints: BoxConstraints.loose(const Size(260, 400)), case BoardSettingAction.groups:
child: GridPropertyList( return GridGroupList(
gridId: widget.settingContext.viewId, viewId: widget.settingContext.viewId,
fieldController: widget.settingContext.fieldController, fieldController: widget.settingContext.fieldController,
), onDismissed: () {
); widget.popoverController.close();
},
);
case BoardSettingAction.properties:
return GridPropertyList(
gridId: widget.settingContext.viewId,
fieldController: widget.settingContext.fieldController,
);
}
} }
return OverlayContainer( return BoardSettingList(
constraints: BoxConstraints.loose(const Size(140, 400)), settingContext: widget.settingContext,
child: BoardSettingList( onAction: (action, settingContext) {
settingContext: widget.settingContext, setState(() => _action = action);
onAction: (action, settingContext) { },
switch (action) {
case BoardSettingAction.groups:
break;
case BoardSettingAction.properties:
setState(() {
_showGridPropertyList = true;
});
break;
}
},
),
); );
} }
} }

View File

@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/field_controller.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/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -40,15 +41,30 @@ class BoardToolbar extends StatelessWidget {
} }
} }
class _SettingButton extends StatelessWidget { class _SettingButton extends StatefulWidget {
final BoardSettingContext settingContext; final BoardSettingContext settingContext;
const _SettingButton({required this.settingContext, Key? key}) const _SettingButton({required this.settingContext, Key? key})
: super(key: key); : super(key: key);
@override
State<_SettingButton> createState() => _SettingButtonState();
}
class _SettingButtonState extends State<_SettingButton> {
late PopoverController popoverController;
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.read<AppTheme>(); final theme = context.read<AppTheme>();
return Popover( return AppFlowyStylePopover(
controller: popoverController,
constraints: BoxConstraints.loose(const Size(260, 400)),
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
child: FlowyIconButton( child: FlowyIconButton(
hoverColor: theme.hover, hoverColor: theme.hover,
@ -61,7 +77,8 @@ class _SettingButton extends StatelessWidget {
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return BoardSettingListPopover( return BoardSettingListPopover(
settingContext: settingContext, settingContext: widget.settingContext,
popoverController: popoverController,
); );
}, },
); );

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)), cellContext: widget.cellController,
child: _CellCalendarWidget( dateTypeOptionPB: _dateTypeOptionPB!,
cellContext: widget.cellController,
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)), dateTypeOptionPB: dateTypeOptionPB,
child: _CalDateTimeSetting( onEvent: (event) => context.read<DateCalBloc>().add(event),
dateTypeOptionPB: dateTypeOptionPB,
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,18 +205,14 @@ 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( width: SelectOptionCellEditor.editorPanelWidth,
Size(SelectOptionCellEditor.editorPanelWidth, 300)), child: SelectOptionCellEditor(
child: SizedBox( cellController: widget.cellControllerBuilder.build()
width: SelectOptionCellEditor.editorPanelWidth, as GridSelectOptionCellController,
child: SelectOptionCellEditor( onDismissed: () {
cellController: widget.cellControllerBuilder.build() widget.onFocus?.call(false);
as GridSelectOptionCellController, },
onDismissed: () {
widget.onFocus?.call(false);
},
),
), ),
); );
}, },

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,23 +287,20 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return SelectOptionTypeOptionEditor(
constraints: BoxConstraints.loose(const Size(200, 300)), option: widget.option,
child: SelectOptionTypeOptionEditor( onDeleted: () {
option: widget.option, context
onDeleted: () { .read<SelectOptionCellEditorBloc>()
context .add(SelectOptionEditorEvent.deleteOption(widget.option));
.read<SelectOptionCellEditorBloc>() },
.add(SelectOptionEditorEvent.deleteOption(widget.option)); onUpdated: (updatedOption) {
}, context
onUpdated: (updatedOption) { .read<SelectOptionCellEditorBloc>()
context .add(SelectOptionEditorEvent.updateOption(updatedOption));
.read<SelectOptionCellEditorBloc>() },
.add(SelectOptionEditorEvent.updateOption(updatedOption)); key: ValueKey(widget.option
}, .id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
key: ValueKey(widget.option
.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
),
); );
}, },
); );

View File

@ -1,6 +1,5 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/application/cell/url_cell_editor_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/url_cell_editor_bloc.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
@ -79,15 +78,12 @@ class URLEditorPopover extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return OverlayContainer( return SizedBox(
constraints: BoxConstraints.loose(const Size(300, 160)), width: 200,
child: SizedBox( child: Padding(
width: 200, padding: const EdgeInsets.all(6),
child: Padding( child: URLCellEditor(
padding: const EdgeInsets.all(6), cellController: cellController,
child: URLCellEditor(
cellController: cellController,
),
), ),
), ),
); );

View File

@ -6,6 +6,7 @@ import 'package:appflowy_popover/popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -129,8 +130,9 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
), ),
); );
return Popover( return AppFlowyStylePopover(
controller: _popoverController, controller: _popoverController,
constraints: BoxConstraints.loose(const Size(300, 160)),
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
offset: const Offset(0, 20), offset: const Offset(0, 20),
child: SizedBox.expand( child: SizedBox.expand(
@ -214,7 +216,8 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Popover( return AppFlowyStylePopover(
constraints: BoxConstraints.loose(const Size(300, 160)),
controller: _popoverController, controller: _popoverController,
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,

View File

@ -163,22 +163,20 @@ class _DeleteFieldButton extends StatelessWidget {
} }
Widget _wrapPopover(Widget widget) { Widget _wrapPopover(Widget widget) {
return Popover( return AppFlowyStylePopover(
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
constraints: BoxConstraints.loose(const Size(400, 240)),
mutex: popoverMutex, mutex: popoverMutex,
direction: PopoverDirection.center, direction: PopoverDirection.center,
popupBuilder: (popupContext) { popupBuilder: (popupContext) {
return OverlayContainer( return PopoverAlertView(
constraints: BoxConstraints.loose(const Size(400, 240)), title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
child: PopoverAlertView( cancel: () => popoverMutex.state?.close(),
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(), confirm: () {
cancel: () => popoverMutex.state?.close(), onDeleted?.call();
confirm: () { popoverMutex.state?.close();
onDeleted?.call(); },
popoverMutex.state?.close(); popoverMutex: popoverMutex,
},
popoverMutex: popoverMutex,
),
); );
}, },
child: widget, child: widget,

View File

@ -1,3 +1,4 @@
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.dart';
@ -25,7 +26,7 @@ class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate {
fieldType: fieldType, fieldType: fieldType,
onSelectField: (fieldType) { onSelectField: (fieldType) {
onSelectField(fieldType); onSelectField(fieldType);
FlowyOverlay.of(context).remove(FieldTypeList.identifier()); PopoverContainer.of(context).closeAll();
}, },
); );
}).toList(); }).toList();

View File

@ -64,18 +64,15 @@ 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: PopoverTriggerActionFlags.click, triggerActions: 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,7 +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_web.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.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';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
@ -176,9 +176,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(),
@ -192,13 +193,10 @@ class CreateFieldButton extends StatelessWidget {
), ),
), ),
popupBuilder: (BuildContext popover) { popupBuilder: (BuildContext popover) {
return OverlayContainer( return FieldEditor(
constraints: BoxConstraints.loose(const Size(240, 200)), gridId: gridId,
child: FieldEditor( fieldName: "",
gridId: gridId, typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
fieldName: "",
typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
),
); );
}, },
); );

View File

@ -62,23 +62,21 @@ 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),
constraints: BoxConstraints.loose(const Size(460, 440)),
popupBuilder: (popoverContext) { popupBuilder: (popoverContext) {
return OverlayContainer( return DateFormatList(
constraints: BoxConstraints.loose(const Size(460, 440)), selectedFormat: dataFormat,
child: DateFormatList( onSelected: (format) {
selectedFormat: dataFormat, context
onSelected: (format) { .read<DateTypeOptionBloc>()
context .add(DateTypeOptionEvent.didSelectDateFormat(format));
.read<DateTypeOptionBloc>() PopoverContainer.of(popoverContext).closeAll();
.add(DateTypeOptionEvent.didSelectDateFormat(format)); },
PopoverContainerState.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),
constraints: BoxConstraints.loose(const Size(460, 440)),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return TimeFormatList(
constraints: BoxConstraints.loose(const Size(460, 440)), selectedFormat: timeFormat,
child: TimeFormatList( onSelected: (format) {
selectedFormat: timeFormat, context
onSelected: (format) { .read<DateTypeOptionBloc>()
context .add(DateTypeOptionEvent.didSelectTimeFormat(format));
.read<DateTypeOptionBloc>() PopoverContainer.of(popoverContext).closeAll();
.add(DateTypeOptionEvent.didSelectTimeFormat(format)); },
PopoverContainerState.of(popoverContext).closeAll();
}),
); );
}, },
child: TimeFormatButton(timeFormat: timeFormat), child: TimeFormatButton(timeFormat: timeFormat),

View File

@ -41,7 +41,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
return SelectOptionTypeOptionWidget( return SelectOptionTypeOptionWidget(
options: selectOptionAction.typeOption.options, options: selectOptionAction.typeOption.options,
beginEdit: () { beginEdit: () {
PopoverContainerState.of(context).closeAll(); PopoverContainer.of(context).closeAll();
}, },
popoverMutex: popoverMutex, popoverMutex: popoverMutex,
typeOptionAction: selectOptionAction, typeOptionAction: selectOptionAction,

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,17 +77,14 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return NumberFormatList(
constraints: BoxConstraints.loose(const Size(460, 440)), onSelected: (format) {
child: NumberFormatList( context
onSelected: (format) { .read<NumberTypeOptionBloc>()
context .add(NumberTypeOptionEvent.didSelectFormat(format));
.read<NumberTypeOptionBloc>() PopoverContainer.of(popoverContext).closeAll();
.add(NumberTypeOptionEvent.didSelectFormat(format)); },
PopoverContainerState.of(popoverContext).closeAll(); selectedFormat: state.typeOption.format,
},
selectedFormat: state.typeOption.format,
),
); );
}, },
); );

View File

@ -2,7 +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_web.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.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';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
@ -180,10 +180,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,24 +201,21 @@ class _OptionCellState extends State<_OptionCell> {
), ),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return OverlayContainer( return SelectOptionTypeOptionEditor(
constraints: BoxConstraints.loose(const Size(460, 440)), option: widget.option,
child: SelectOptionTypeOptionEditor( onDeleted: () {
option: widget.option, context
onDeleted: () { .read<SelectOptionTypeOptionBloc>()
context .add(SelectOptionTypeOptionEvent.deleteOption(widget.option));
.read<SelectOptionTypeOptionBloc>() PopoverContainer.of(popoverContext).closeAll();
.add(SelectOptionTypeOptionEvent.deleteOption(widget.option)); },
PopoverContainerState.of(popoverContext).closeAll(); onUpdated: (updatedOption) {
}, context
onUpdated: (updatedOption) { .read<SelectOptionTypeOptionBloc>()
context .add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
.read<SelectOptionTypeOptionBloc>() PopoverContainer.of(popoverContext).closeAll();
.add(SelectOptionTypeOptionEvent.updateOption(updatedOption)); },
PopoverContainerState.of(popoverContext).closeAll(); key: ValueKey(widget.option.id),
},
key: ValueKey(widget.option.id),
),
); );
}, },
); );

View File

@ -40,7 +40,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
return SelectOptionTypeOptionWidget( return SelectOptionTypeOptionWidget(
options: selectOptionAction.typeOption.options, options: selectOptionAction.typeOption.options,
beginEdit: () { beginEdit: () {
PopoverContainerState.of(context).closeAll(); PopoverContainer.of(context).closeAll();
}, },
popoverMutex: popoverMutex, popoverMutex: popoverMutex,
typeOptionAction: selectOptionAction, typeOptionAction: selectOptionAction,

View File

@ -146,18 +146,15 @@ class _PropertyList extends StatelessWidget {
}); });
}, },
onOpened: (controller) { onOpened: (controller) {
return OverlayContainer( return FieldEditor(
constraints: BoxConstraints.loose(const Size(240, 200)), gridId: viewId,
child: FieldEditor( typeOptionLoader: NewFieldTypeOptionLoader(gridId: viewId),
gridId: viewId, onDeleted: (fieldId) {
typeOptionLoader: NewFieldTypeOptionLoader(gridId: viewId), controller.close();
onDeleted: (fieldId) { context
controller.close(); .read<RowDetailBloc>()
context .add(RowDetailEvent.deleteField(fieldId));
.read<RowDetailBloc>() },
.add(RowDetailEvent.deleteField(fieldId));
},
),
); );
}, },
), ),
@ -168,28 +165,41 @@ class _PropertyList extends StatelessWidget {
} }
} }
class _CreateFieldButton extends StatelessWidget { class _CreateFieldButton extends StatefulWidget {
final String viewId; final String viewId;
final Widget Function(PopoverController) onOpened; final Widget Function(PopoverController) onOpened;
final VoidCallback onClosed; final VoidCallback onClosed;
final PopoverController popoverController = PopoverController();
_CreateFieldButton({ const _CreateFieldButton({
required this.viewId, required this.viewId,
required this.onOpened, required this.onOpened,
required this.onClosed, required this.onClosed,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@override
State<_CreateFieldButton> createState() => _CreateFieldButtonState();
}
class _CreateFieldButtonState extends State<_CreateFieldButton> {
late PopoverController popoverController;
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.read<AppTheme>(); final theme = context.read<AppTheme>();
return Popover( return AppFlowyStylePopover(
constraints: BoxConstraints.loose(const Size(240, 200)),
controller: popoverController, controller: popoverController,
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
direction: PopoverDirection.topWithLeftAligned, direction: PopoverDirection.topWithLeftAligned,
onClose: onClosed, onClose: widget.onClosed,
child: Container( child: Container(
height: 40, height: 40,
decoration: _makeBoxDecoration(context), decoration: _makeBoxDecoration(context),
@ -203,7 +213,8 @@ class _CreateFieldButton extends StatelessWidget {
leftIcon: svgWidget("home/add"), leftIcon: svgWidget("home/add"),
), ),
), ),
popupBuilder: (BuildContext context) => onOpened(popoverController), popupBuilder: (BuildContext context) =>
widget.onOpened(popoverController),
); );
} }

View File

@ -3,7 +3,6 @@ import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/header/field_type_extension.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/header/field_type_extension.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/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';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
@ -15,9 +14,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
class GridGroupList extends StatelessWidget { class GridGroupList extends StatelessWidget {
final String viewId; final String viewId;
final GridFieldController fieldController; final GridFieldController fieldController;
final VoidCallback onDismissed;
const GridGroupList({ const GridGroupList({
required this.viewId, required this.viewId,
required this.fieldController, required this.fieldController,
required this.onDismissed,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -33,6 +34,7 @@ class GridGroupList extends StatelessWidget {
final cells = state.fieldContexts.map((fieldContext) { final cells = state.fieldContexts.map((fieldContext) {
Widget cell = _GridGroupCell( Widget cell = _GridGroupCell(
fieldContext: fieldContext, fieldContext: fieldContext,
onSelected: () => onDismissed(),
key: ValueKey(fieldContext.id), key: ValueKey(fieldContext.id),
); );
@ -56,29 +58,16 @@ class GridGroupList extends StatelessWidget {
), ),
); );
} }
void show(BuildContext context) {
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
constraints: BoxConstraints.loose(const Size(260, 400)),
child: this,
),
identifier: identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomRight,
style: FlowyOverlayStyle(blur: false),
);
}
static String identifier() {
return (GridGroupList).toString();
}
} }
class _GridGroupCell extends StatelessWidget { class _GridGroupCell extends StatelessWidget {
final VoidCallback onSelected;
final GridFieldContext fieldContext; final GridFieldContext fieldContext;
const _GridGroupCell({required this.fieldContext, Key? key}) const _GridGroupCell({
: super(key: key); required this.fieldContext,
required this.onSelected,
Key? key,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -97,8 +86,10 @@ class _GridGroupCell extends StatelessWidget {
child: FlowyButton( child: FlowyButton(
text: FlowyText.medium(fieldContext.name, fontSize: 12), text: FlowyText.medium(fieldContext.name, fontSize: 12),
hoverColor: theme.hover, hoverColor: theme.hover,
leftIcon: svgWidget(fieldContext.fieldType.iconName(), leftIcon: svgWidget(
color: theme.iconColor), fieldContext.fieldType.iconName(),
color: theme.iconColor,
),
rightIcon: rightIcon, rightIcon: rightIcon,
onTap: () { onTap: () {
context.read<GridGroupBloc>().add( context.read<GridGroupBloc>().add(
@ -107,7 +98,8 @@ class _GridGroupCell extends StatelessWidget {
fieldContext.fieldType, fieldContext.fieldType,
), ),
); );
FlowyOverlay.of(context).remove(GridGroupList.identifier()); onSelected();
// FlowyOverlay.of(context).remove(GridGroupList.identifier());
}, },
), ),
); );

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)), gridId: gridId,
child: FieldEditor( fieldName: fieldContext.name,
gridId: gridId, typeOptionLoader:
fieldName: fieldContext.name, FieldTypeOptionLoader(gridId: gridId, field: fieldContext.field),
typeOptionLoader: FieldTypeOptionLoader(
gridId: gridId, field: fieldContext.field),
),
); );
}, },
); );

View File

@ -53,7 +53,8 @@ class _SettingButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Popover( return AppFlowyStylePopover(
constraints: BoxConstraints.loose(const Size(260, 400)),
triggerActions: PopoverTriggerActionFlags.click, triggerActions: PopoverTriggerActionFlags.click,
offset: const Offset(0, 10), offset: const Offset(0, 10),
child: FlowyIconButton( child: FlowyIconButton(
@ -87,25 +88,19 @@ class _GridSettingListPopoverState extends State<_GridSettingListPopover> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_action == GridSettingAction.properties) { if (_action == GridSettingAction.properties) {
return OverlayContainer( return GridPropertyList(
constraints: BoxConstraints.loose(const Size(260, 400)), gridId: widget.settingContext.gridId,
child: GridPropertyList( fieldController: widget.settingContext.fieldController,
gridId: widget.settingContext.gridId,
fieldController: widget.settingContext.fieldController,
),
); );
} }
return OverlayContainer( return GridSettingList(
constraints: BoxConstraints.loose(const Size(140, 400)), settingContext: widget.settingContext,
child: GridSettingList( onAction: (action, settingContext) {
settingContext: widget.settingContext, setState(() {
onAction: (action, settingContext) { _action = action;
setState(() { });
_action = action; },
});
},
),
); );
} }
} }

View File

@ -284,6 +284,15 @@ class PopoverContainer extends StatefulWidget {
@override @override
State<StatefulWidget> createState() => PopoverContainerState(); State<StatefulWidget> createState() => PopoverContainerState();
static PopoverContainerState of(BuildContext context) {
if (context is StatefulElement && context.state is PopoverContainerState) {
return context.state as PopoverContainerState;
}
final PopoverContainerState? result =
context.findAncestorStateOfType<PopoverContainerState>();
return result!;
}
} }
class PopoverContainerState extends State<PopoverContainer> { class PopoverContainerState extends State<PopoverContainer> {
@ -302,13 +311,4 @@ class PopoverContainerState extends State<PopoverContainer> {
close() => widget.onClose(); close() => widget.onClose();
closeAll() => widget.onCloseAll(); closeAll() => widget.onCloseAll();
static PopoverContainerState of(BuildContext context) {
if (context is StatefulElement && context.state is PopoverContainerState) {
return context.state as PopoverContainerState;
}
final PopoverContainerState? result =
context.findAncestorStateOfType<PopoverContainerState>();
return result!;
}
} }

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,48 @@
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) {
final child = popupBuilder(context);
debugPrint('$child popover');
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),
)));
}
}

View File

@ -27,6 +27,8 @@ dependencies:
path: flowy_infra_ui_platform_interface path: flowy_infra_ui_platform_interface
flowy_infra_ui_web: flowy_infra_ui_web:
path: flowy_infra_ui_web path: flowy_infra_ui_web
appflowy_popover:
path: ../appflowy_popover
# Flowy packages # Flowy packages
flowy_infra: flowy_infra: