refactor: replace FlowyOverlay with AppFlowyPopover in select option

This commit is contained in:
nathan 2022-09-18 11:46:00 +08:00
parent 3a1148d11a
commit 6c27b5455e
3 changed files with 112 additions and 135 deletions

View File

@ -2,6 +2,8 @@ import 'package:app_flowy/plugins/board/application/card/board_select_option_cel
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -26,9 +28,11 @@ class BoardSelectOptionCell extends StatefulWidget with EditableCell {
class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
late BoardSelectOptionCellBloc _cellBloc;
late PopoverController _popover;
@override
void initState() {
_popover = PopoverController();
final cellController =
widget.cellControllerBuilder.build() as GridSelectOptionCellController;
_cellBloc = BoardSelectOptionCellBloc(cellController: cellController)
@ -41,43 +45,60 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardSelectOptionCellBloc, BoardSelectOptionCellState>(
buildWhen: (previous, current) {
return previous.selectedOptions != current.selectedOptions;
},
builder: (context, state) {
if (state.selectedOptions
.where((element) => element.id == widget.groupId)
.isNotEmpty ||
state.selectedOptions.isEmpty) {
return const SizedBox();
} else {
final children = state.selectedOptions
.map(
(option) => SelectOptionTag.fromOption(
context: context,
option: option,
onSelected: () {
SelectOptionCellEditor.show(
context: context,
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
);
},
),
)
.toList();
buildWhen: (previous, current) {
return previous.selectedOptions != current.selectedOptions;
}, builder: (context, state) {
// Returns SizedBox if the content of the cell is empty
if (_isEmpty(state)) return const SizedBox();
return IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SizedBox.expand(
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
),
final children = state.selectedOptions.map(
(option) {
final tag = SelectOptionTag.fromOption(
context: context,
option: option,
onSelected: () => _popover.show(),
);
}
},
),
return _wrapPopover(tag);
},
).toList();
return IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SizedBox.expand(
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
),
);
}),
);
}
bool _isEmpty(BoardSelectOptionCellState state) {
// The cell should hide if the option id is equal to the groupId.
final isInGroup = state.selectedOptions
.where((element) => element.id == widget.groupId)
.isNotEmpty;
return isInGroup || state.selectedOptions.isEmpty;
}
Widget _wrapPopover(Widget child) {
final constraints = BoxConstraints.loose(Size(
SelectOptionCellEditor.editorPanelWidth,
300,
));
return AppFlowyStylePopover(
controller: _popover,
constraints: constraints,
direction: PopoverDirection.bottomWithLeftAligned,
popupBuilder: (BuildContext context) {
return SelectOptionCellEditor(
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
);
},
onClose: () {},
child: child,
);
}

View File

@ -164,67 +164,65 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
final Widget child;
if (widget.selectOptions.isEmpty && widget.cellStyle != null) {
child = Align(
alignment: Alignment.centerLeft,
child: FlowyText.medium(
widget.cellStyle!.placeholder,
fontSize: 14,
color: theme.shader3,
),
);
} else {
child = Align(
alignment: Alignment.centerLeft,
child: Wrap(
spacing: 4,
runSpacing: 2,
children: widget.selectOptions
.map((option) => SelectOptionTag.fromOption(
context: context,
option: option,
))
.toList(),
),
);
}
Widget child = _buildOptions(theme, context);
return Stack(
alignment: AlignmentDirectional.center,
fit: StackFit.expand,
children: [
AppFlowyStylePopover(
controller: _popover,
constraints: BoxConstraints.loose(
Size(SelectOptionCellEditor.editorPanelWidth, 300)),
offset: const Offset(0, 20),
direction: PopoverDirection.bottomWithLeftAligned,
// triggerActions: PopoverTriggerActionFlags.c,
popupBuilder: (BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.onFocus?.call(true);
});
return SizedBox(
width: SelectOptionCellEditor.editorPanelWidth,
child: SelectOptionCellEditor(
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
onDismissed: () {
widget.onFocus?.call(false);
},
),
);
},
onClose: () {
widget.onFocus?.call(false);
},
child: child,
),
InkWell(onTap: () {
_popover.show();
}),
_wrapPopover(child),
InkWell(onTap: () => _popover.show()),
],
);
}
Widget _wrapPopover(Widget child) {
final constraints = BoxConstraints.loose(Size(
SelectOptionCellEditor.editorPanelWidth,
300,
));
return AppFlowyStylePopover(
controller: _popover,
constraints: constraints,
direction: PopoverDirection.bottomWithLeftAligned,
popupBuilder: (BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onFocus?.call(true);
});
return SelectOptionCellEditor(
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
);
},
onClose: () => widget.onFocus?.call(false),
child: child,
);
}
Widget _buildOptions(AppTheme theme, BuildContext context) {
final Widget child;
if (widget.selectOptions.isEmpty && widget.cellStyle != null) {
child = FlowyText.medium(
widget.cellStyle!.placeholder,
fontSize: 14,
color: theme.shader3,
);
} else {
final children = widget.selectOptions.map(
(option) {
return SelectOptionTag.fromOption(
context: context,
option: option,
);
},
).toList();
child = Wrap(
spacing: 4,
runSpacing: 2,
children: children,
);
}
return Align(alignment: Alignment.centerLeft, child: child);
}
}

View File

@ -25,17 +25,13 @@ import 'text_field.dart';
const double _editorPanelWidth = 300;
class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
class SelectOptionCellEditor extends StatelessWidget {
final GridSelectOptionCellController cellController;
final VoidCallback? onDismissed;
static double editorPanelWidth = 300;
const SelectOptionCellEditor({
required this.cellController,
this.onDismissed,
Key? key,
}) : super(key: key);
const SelectOptionCellEditor({required this.cellController, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -60,44 +56,6 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
),
);
}
static void show({
required BuildContext context,
required GridSelectOptionCellController cellController,
VoidCallback? onDismissed,
}) {
SelectOptionCellEditor.remove(context);
final editor = SelectOptionCellEditor(
cellController: cellController,
onDismissed: onDismissed,
);
//
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
constraints: BoxConstraints.loose(const Size(_editorPanelWidth, 300)),
child: SizedBox(width: _editorPanelWidth, child: editor),
),
identifier: SelectOptionCellEditor.identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomWithCenterAligned,
delegate: editor,
);
}
static void remove(BuildContext context) {
FlowyOverlay.of(context).remove(identifier());
}
static String identifier() {
return (SelectOptionCellEditor).toString();
}
@override
bool asBarrier() => true;
@override
void didRemove() => onDismissed?.call();
}
class _OptionList extends StatelessWidget {