mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: replace FlowyOverlay with AppFlowyPopover in select option
This commit is contained in:
parent
3a1148d11a
commit
6c27b5455e
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user