mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add mutex to property list
This commit is contained in:
parent
4c31c0dcf0
commit
8229371f63
@ -1,6 +1,7 @@
|
||||
import 'dart:collection';
|
||||
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/cell/select_option_editor_bloc.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
@ -228,30 +229,46 @@ class _CreateOptionCell extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SelectOptionCell extends StatelessWidget {
|
||||
class _SelectOptionCell extends StatefulWidget {
|
||||
final SelectOptionPB option;
|
||||
final bool isSelected;
|
||||
const _SelectOptionCell(this.option, this.isSelected, {Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<_SelectOptionCell> createState() => _SelectOptionCellState();
|
||||
}
|
||||
|
||||
class _SelectOptionCellState extends State<_SelectOptionCell> {
|
||||
late PopoverController _popoverController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_popoverController = PopoverController();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return SizedBox(
|
||||
return Popover(
|
||||
controller: _popoverController,
|
||||
offset: const Offset(20, 0),
|
||||
child: SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
fit: FlexFit.loose,
|
||||
child: SelectOptionTagCell(
|
||||
option: option,
|
||||
option: widget.option,
|
||||
onSelected: (option) {
|
||||
context
|
||||
.read<SelectOptionCellEditorBloc>()
|
||||
.add(SelectOptionEditorEvent.selectOption(option.id));
|
||||
},
|
||||
children: [
|
||||
if (isSelected)
|
||||
if (widget.isSelected)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 6),
|
||||
child: svgWidget("grid/checkmark"),
|
||||
@ -261,43 +278,33 @@ class _SelectOptionCell extends StatelessWidget {
|
||||
),
|
||||
FlowyIconButton(
|
||||
width: 30,
|
||||
onPressed: () => _showEditPannel(context),
|
||||
onPressed: () => _popoverController.show(),
|
||||
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
||||
icon: svgWidget("editor/details", color: theme.iconColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showEditPannel(BuildContext context) {
|
||||
final pannel = SelectOptionTypeOptionEditor(
|
||||
option: option,
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return OverlayContainer(
|
||||
constraints: BoxConstraints.loose(const Size(200, 300)),
|
||||
child: SelectOptionTypeOptionEditor(
|
||||
option: widget.option,
|
||||
onDeleted: () {
|
||||
context
|
||||
.read<SelectOptionCellEditorBloc>()
|
||||
.add(SelectOptionEditorEvent.deleteOption(option));
|
||||
.add(SelectOptionEditorEvent.deleteOption(widget.option));
|
||||
},
|
||||
onUpdated: (updatedOption) {
|
||||
context
|
||||
.read<SelectOptionCellEditorBloc>()
|
||||
.add(SelectOptionEditorEvent.updateOption(updatedOption));
|
||||
},
|
||||
key: ValueKey(option
|
||||
key: ValueKey(widget.option
|
||||
.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
|
||||
);
|
||||
final overlayIdentifier = (SelectOptionTypeOptionEditor).toString();
|
||||
|
||||
FlowyOverlay.of(context).remove(overlayIdentifier);
|
||||
FlowyOverlay.of(context).insertWithAnchor(
|
||||
widget: OverlayContainer(
|
||||
child: pannel,
|
||||
constraints: BoxConstraints.loose(const Size(200, 300)),
|
||||
),
|
||||
identifier: overlayIdentifier,
|
||||
anchorContext: context,
|
||||
anchorDirection: AnchorDirection.rightWithCenterAligned,
|
||||
anchorOffset: Offset(2 * overlayContainerPadding.left, 0),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class _GridFieldCellState extends State<GridFieldCell> {
|
||||
builder: (context, state) {
|
||||
final button = Popover(
|
||||
controller: popover,
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
child: FieldCellButton(
|
||||
field: state.field,
|
||||
onTap: () => popover.show(),
|
||||
|
@ -2,7 +2,6 @@ import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart'
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -2,8 +2,10 @@ import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/prelude.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.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/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
@ -154,19 +156,25 @@ class CreateFieldButton extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
|
||||
return FlowyButton(
|
||||
return Popover(
|
||||
triggerActions: PopoverTriggerActionFlags.click,
|
||||
direction: PopoverDirection.bottomWithRightAligned,
|
||||
child: FlowyButton(
|
||||
text: const FlowyText.medium('New column', fontSize: 12),
|
||||
hoverColor: theme.shader6,
|
||||
onTap: () {
|
||||
// FieldEditorPopOver.show(
|
||||
// context,
|
||||
// anchorContext: context,
|
||||
// gridId: gridId,
|
||||
// fieldName: "",
|
||||
// typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
|
||||
// )
|
||||
},
|
||||
onTap: () {},
|
||||
leftIcon: svgWidget("home/add"),
|
||||
),
|
||||
popupBuilder: (BuildContext popover) {
|
||||
return OverlayContainer(
|
||||
constraints: BoxConstraints.loose(const Size(240, 200)),
|
||||
child: FieldEditor(
|
||||
gridId: gridId,
|
||||
fieldName: "",
|
||||
typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
context
|
||||
.read<DateTypeOptionBloc>()
|
||||
.add(DateTypeOptionEvent.didSelectDateFormat(format));
|
||||
PopoverContainerState.of(popoverContext).closeAll();
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -100,7 +101,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
|
||||
context
|
||||
.read<DateTypeOptionBloc>()
|
||||
.add(DateTypeOptionEvent.didSelectTimeFormat(format));
|
||||
PopoverContainerState.of(popoverContext).close();
|
||||
PopoverContainerState.of(popoverContext).closeAll();
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/multi_select_type_option.dart';
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
|
||||
import '../field_type_option_editor.dart';
|
||||
import 'builder.dart';
|
||||
@ -39,7 +40,10 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return SelectOptionTypeOptionWidget(
|
||||
options: selectOptionAction.typeOption.options,
|
||||
beginEdit: () => overlayDelegate.hideOverlay(context),
|
||||
beginEdit: () {
|
||||
overlayDelegate.hideOverlay(context);
|
||||
PopoverContainerState.of(context).closeAll();
|
||||
},
|
||||
overlayDelegate: overlayDelegate,
|
||||
typeOptionAction: selectOptionAction,
|
||||
// key: ValueKey(state.typeOption.hashCode),
|
||||
|
@ -79,7 +79,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
popupBuilder: (BuildContext context) {
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return OverlayContainer(
|
||||
constraints: BoxConstraints.loose(const Size(460, 440)),
|
||||
child: NumberFormatList(
|
||||
@ -87,6 +87,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
|
||||
context
|
||||
.read<NumberTypeOptionBloc>()
|
||||
.add(NumberTypeOptionEvent.didSelectFormat(format));
|
||||
PopoverContainerState.of(popoverContext).closeAll();
|
||||
},
|
||||
selectedFormat: state.typeOption.format,
|
||||
),
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/select_option_type_option_bloc.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.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/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
@ -143,47 +145,41 @@ class _OptionList extends StatelessWidget {
|
||||
_OptionCell _makeOptionCell(BuildContext context, SelectOptionPB option) {
|
||||
return _OptionCell(
|
||||
option: option,
|
||||
onSelected: (option) {
|
||||
final pannel = SelectOptionTypeOptionEditor(
|
||||
option: option,
|
||||
onDeleted: () {
|
||||
delegate.hideOverlay(context);
|
||||
context
|
||||
.read<SelectOptionTypeOptionBloc>()
|
||||
.add(SelectOptionTypeOptionEvent.deleteOption(option));
|
||||
},
|
||||
onUpdated: (updatedOption) {
|
||||
delegate.hideOverlay(context);
|
||||
context
|
||||
.read<SelectOptionTypeOptionBloc>()
|
||||
.add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
|
||||
},
|
||||
key: ValueKey(option.id),
|
||||
);
|
||||
delegate.showOverlay(context, pannel);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionCell extends StatelessWidget {
|
||||
class _OptionCell extends StatefulWidget {
|
||||
final SelectOptionPB option;
|
||||
final Function(SelectOptionPB) onSelected;
|
||||
const _OptionCell({
|
||||
required this.option,
|
||||
required this.onSelected,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
const _OptionCell({required this.option, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_OptionCell> createState() => _OptionCellState();
|
||||
}
|
||||
|
||||
class _OptionCellState extends State<_OptionCell> {
|
||||
late PopoverController _popoverController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_popoverController = PopoverController();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
|
||||
return SizedBox(
|
||||
return Popover(
|
||||
controller: _popoverController,
|
||||
offset: const Offset(20, 0),
|
||||
child: SizedBox(
|
||||
height: GridSize.typeOptionItemHeight,
|
||||
child: SelectOptionTagCell(
|
||||
option: option,
|
||||
onSelected: onSelected,
|
||||
option: widget.option,
|
||||
onSelected: (SelectOptionPB pb) {
|
||||
_popoverController.show();
|
||||
},
|
||||
children: [
|
||||
svgWidget(
|
||||
"grid/details",
|
||||
@ -191,6 +187,28 @@ class _OptionCell extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return OverlayContainer(
|
||||
constraints: BoxConstraints.loose(const Size(460, 440)),
|
||||
child: SelectOptionTypeOptionEditor(
|
||||
option: widget.option,
|
||||
onDeleted: () {
|
||||
context
|
||||
.read<SelectOptionTypeOptionBloc>()
|
||||
.add(SelectOptionTypeOptionEvent.deleteOption(widget.option));
|
||||
PopoverContainerState.of(popoverContext).closeAll();
|
||||
},
|
||||
onUpdated: (updatedOption) {
|
||||
context
|
||||
.read<SelectOptionTypeOptionBloc>()
|
||||
.add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
|
||||
PopoverContainerState.of(popoverContext).closeAll();
|
||||
},
|
||||
key: ValueKey(widget.option.id),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/single_sele
|
||||
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../field_type_option_editor.dart';
|
||||
import 'package:appflowy_popover/popover.dart';
|
||||
import 'builder.dart';
|
||||
import 'select_option.dart';
|
||||
|
||||
@ -38,7 +39,10 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return SelectOptionTypeOptionWidget(
|
||||
options: selectOptionAction.typeOption.options,
|
||||
beginEdit: () => overlayDelegate.hideOverlay(context),
|
||||
beginEdit: () {
|
||||
overlayDelegate.hideOverlay(context);
|
||||
PopoverContainerState.of(context).closeAll();
|
||||
},
|
||||
overlayDelegate: overlayDelegate,
|
||||
typeOptionAction: selectOptionAction,
|
||||
// key: ValueKey(state.typeOption.hashCode),
|
||||
|
@ -19,7 +19,7 @@ import 'package:styled_widget/styled_widget.dart';
|
||||
import '../../../application/field/field_cache.dart';
|
||||
import '../../layout/sizes.dart';
|
||||
|
||||
class GridPropertyList extends StatelessWidget {
|
||||
class GridPropertyList extends StatefulWidget {
|
||||
final String gridId;
|
||||
final GridFieldCache fieldCache;
|
||||
const GridPropertyList({
|
||||
@ -28,17 +28,34 @@ class GridPropertyList extends StatelessWidget {
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _GridPropertyListState();
|
||||
}
|
||||
|
||||
class _GridPropertyListState extends State<GridPropertyList> {
|
||||
late PopoverMutex _popoverMutex;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_popoverMutex = PopoverMutex();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
getIt<GridPropertyBloc>(param1: gridId, param2: fieldCache)
|
||||
create: (context) => getIt<GridPropertyBloc>(
|
||||
param1: widget.gridId, param2: widget.fieldCache)
|
||||
..add(const GridPropertyEvent.initial()),
|
||||
child: BlocBuilder<GridPropertyBloc, GridPropertyState>(
|
||||
builder: (context, state) {
|
||||
final cells = state.fields.map((field) {
|
||||
return _GridPropertyCell(
|
||||
gridId: gridId, field: field, key: ValueKey(field.id));
|
||||
popoverMutex: _popoverMutex,
|
||||
gridId: widget.gridId,
|
||||
field: field,
|
||||
key: ValueKey(field.id),
|
||||
);
|
||||
}).toList();
|
||||
|
||||
return ListView.separated(
|
||||
@ -60,8 +77,13 @@ class GridPropertyList extends StatelessWidget {
|
||||
class _GridPropertyCell extends StatelessWidget {
|
||||
final FieldPB field;
|
||||
final String gridId;
|
||||
const _GridPropertyCell({required this.gridId, required this.field, Key? key})
|
||||
: super(key: key);
|
||||
final PopoverMutex popoverMutex;
|
||||
const _GridPropertyCell({
|
||||
required this.gridId,
|
||||
required this.field,
|
||||
required this.popoverMutex,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -95,6 +117,7 @@ class _GridPropertyCell extends StatelessWidget {
|
||||
|
||||
Widget _editFieldButton(AppTheme theme, BuildContext context) {
|
||||
return Popover(
|
||||
mutex: popoverMutex,
|
||||
triggerActions: PopoverTriggerActionFlags.click,
|
||||
offset: const Offset(20, 0),
|
||||
child: FlowyButton(
|
||||
|
@ -1,10 +1,7 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy_popover/layout.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import './follower.dart';
|
||||
|
||||
class PopoverMutex {
|
||||
PopoverState? state;
|
||||
@ -128,6 +125,7 @@ class PopoverState extends State<Popover> {
|
||||
offset: widget.offset ?? Offset.zero,
|
||||
popupBuilder: widget.popupBuilder,
|
||||
onClose: () => close(),
|
||||
onCloseAll: () => closeAll(),
|
||||
));
|
||||
|
||||
return Stack(children: children);
|
||||
@ -155,6 +153,10 @@ class PopoverState extends State<Popover> {
|
||||
}
|
||||
}
|
||||
|
||||
closeAll() {
|
||||
_popoverWithMask?.close();
|
||||
}
|
||||
|
||||
@override
|
||||
void deactivate() {
|
||||
debugPrint("deactivate");
|
||||
@ -247,6 +249,7 @@ class PopoverContainer extends StatefulWidget {
|
||||
final PopoverLink popoverLink;
|
||||
final Offset offset;
|
||||
final void Function() onClose;
|
||||
final void Function() onCloseAll;
|
||||
|
||||
const PopoverContainer({
|
||||
Key? key,
|
||||
@ -255,6 +258,7 @@ class PopoverContainer extends StatefulWidget {
|
||||
required this.popoverLink,
|
||||
required this.offset,
|
||||
required this.onClose,
|
||||
required this.onCloseAll,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -274,9 +278,9 @@ class PopoverContainerState extends State<PopoverContainer> {
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
widget.onClose();
|
||||
}
|
||||
close() => widget.onClose();
|
||||
|
||||
closeAll() => widget.onCloseAll();
|
||||
|
||||
static PopoverContainerState of(BuildContext context) {
|
||||
if (context is StatefulElement && context.state is PopoverContainerState) {
|
||||
|
Loading…
Reference in New Issue
Block a user