Skip to content

Commit

Permalink
fix: make the turn into menu and color menu exclusive
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasXu0 committed Nov 4, 2024
1 parent 9a03c7c commit 596b2fc
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ class _DocumentPageState extends State<DocumentPage>

final Path? path = _getPathFromAction(action, editorState);
if (path != null) {
debugPrint('jump to block: $path');
editorState.updateSelectionWithReason(
Selection.collapsed(Position(path: path)),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';

import 'drag_to_reorder/draggable_option_button.dart';

class BlockOptionButton extends StatelessWidget {
class BlockOptionButton extends StatefulWidget {
const BlockOptionButton({
super.key,
required this.blockComponentContext,
Expand All @@ -25,6 +25,16 @@ class BlockOptionButton extends StatelessWidget {
final EditorState editorState;
final Map<String, BlockComponentBuilder> blockComponentBuilder;

@override
State<BlockOptionButton> createState() => _BlockOptionButtonState();
}

class _BlockOptionButtonState extends State<BlockOptionButton> {
// the mutex is used to ensure that only one popover is open at a time
// for example, when the user is selecting the color, the turn into option
// should not be shown.
final mutex = PopoverMutex();

@override
Widget build(BuildContext context) {
final direction =
Expand All @@ -34,8 +44,8 @@ class BlockOptionButton extends StatelessWidget {
: PopoverDirection.leftWithCenterAligned;
return BlocProvider(
create: (context) => BlockActionOptionCubit(
editorState: editorState,
blockComponentBuilder: blockComponentBuilder,
editorState: widget.editorState,
blockComponentBuilder: widget.blockComponentBuilder,
),
child: BlocBuilder<BlockActionOptionCubit, BlockActionOptionState>(
builder: (context, _) => PopoverActionList<PopoverAction>(
Expand All @@ -55,30 +65,41 @@ class BlockOptionButton extends StatelessWidget {
),
buildChild: (controller) => DraggableOptionButton(
controller: controller,
editorState: editorState,
blockComponentContext: blockComponentContext,
blockComponentBuilder: blockComponentBuilder,
editorState: widget.editorState,
blockComponentContext: widget.blockComponentContext,
blockComponentBuilder: widget.blockComponentBuilder,
),
),
),
);
}

@override
void dispose() {
mutex.dispose();

super.dispose();
}

List<PopoverAction> _buildPopoverActions(BuildContext context) {
return actions.map((e) {
return widget.actions.map((e) {
switch (e) {
case OptionAction.divider:
return DividerOptionAction();
case OptionAction.color:
return ColorOptionAction(editorState: editorState);
return ColorOptionAction(
editorState: widget.editorState,
mutex: mutex,
);
case OptionAction.align:
return AlignOptionAction(editorState: editorState);
return AlignOptionAction(editorState: widget.editorState);
case OptionAction.depth:
return DepthOptionAction(editorState: editorState);
return DepthOptionAction(editorState: widget.editorState);
case OptionAction.turnInto:
return TurnIntoOptionAction(
editorState: editorState,
blockComponentBuilder: blockComponentBuilder,
editorState: widget.editorState,
blockComponentBuilder: widget.blockComponentBuilder,
mutex: mutex,
);
default:
return OptionActionWrapper(e);
Expand All @@ -88,15 +109,17 @@ class BlockOptionButton extends StatelessWidget {

void _onPopoverBuilder() {
keepEditorFocusNotifier.increase();
blockComponentState.alwaysShowActions = true;
widget.blockComponentState.alwaysShowActions = true;
}

void _onPopoverClosed(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
editorState.selectionType = null;
editorState.selection = null;
blockComponentState.alwaysShowActions = false;
widget.editorState.selectionType = null;
widget.editorState.selection = null;
widget.blockComponentState.alwaysShowActions = false;
});

PopoverContainer.maybeOf(context)?.closeAll();
}

void _onActionSelected(
Expand All @@ -110,7 +133,7 @@ class BlockOptionButton extends StatelessWidget {

context.read<BlockActionOptionCubit>().handleAction(
action.inner,
blockComponentContext.node,
widget.blockComponentContext.node,
);
controller.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,62 @@ const optionActionColorDefaultColor = 'appflowy_theme_default_color';
class ColorOptionAction extends CustomActionCell {
ColorOptionAction({
required this.editorState,
required this.mutex,
});

final EditorState editorState;
final PopoverController innerController = PopoverController();
final PopoverMutex mutex;

@override
Widget buildWithContext(
BuildContext context,
PopoverController controller,
PopoverMutex? mutex,
) {
return ColorOptionButton(
editorState: editorState,
mutex: this.mutex,
controller: controller,
);
}
}

class ColorOptionButton extends StatefulWidget {
const ColorOptionButton({
super.key,
required this.editorState,
required this.mutex,
required this.controller,
});

final EditorState editorState;
final PopoverMutex mutex;
final PopoverController controller;

@override
State<ColorOptionButton> createState() => _ColorOptionButtonState();
}

class _ColorOptionButtonState extends State<ColorOptionButton> {
final PopoverController innerController = PopoverController();
bool isOpen = false;

@override
Widget build(BuildContext context) {
return AppFlowyPopover(
asBarrier: true,
controller: innerController,
mutex: mutex,
popupBuilder: (context) => _buildColorOptionMenu(
context,
controller,
),
mutex: widget.mutex,
popupBuilder: (context) {
isOpen = true;
return _buildColorOptionMenu(
context,
widget.controller,
);
},
onClose: () => isOpen = false,
direction: PopoverDirection.rightWithCenterAligned,
offset: const Offset(10, 0),
animationDuration: Durations.short3,
beginScaleFactor: 1.0,
beginOpacity: 0.8,
Expand All @@ -45,7 +80,9 @@ class ColorOptionAction extends CustomActionCell {
),
name: LocaleKeys.document_plugins_optionAction_color.tr(),
onTap: () {
innerController.show();
if (!isOpen) {
innerController.show();
}
},
),
);
Expand All @@ -55,12 +92,12 @@ class ColorOptionAction extends CustomActionCell {
BuildContext context,
PopoverController controller,
) {
final selection = editorState.selection?.normalized;
final selection = widget.editorState.selection?.normalized;
if (selection == null) {
return const SizedBox.shrink();
}

final node = editorState.getNodeAtPath(selection.start.path);
final node = widget.editorState.getNodeAtPath(selection.start.path);
if (node == null) {
return const SizedBox.shrink();
}
Expand All @@ -73,11 +110,11 @@ class ColorOptionAction extends CustomActionCell {
Node node,
PopoverController controller,
) {
final selection = editorState.selection?.normalized;
final selection = widget.editorState.selection?.normalized;
if (selection == null) {
return const SizedBox.shrink();
}
final node = editorState.getNodeAtPath(selection.start.path);
final node = widget.editorState.getNodeAtPath(selection.start.path);
if (node == null) {
return const SizedBox.shrink();
}
Expand Down Expand Up @@ -110,11 +147,11 @@ class ColorOptionAction extends CustomActionCell {
color: AFThemeExtension.of(context).onBackground,
),
onTap: (option, index) async {
final transaction = editorState.transaction;
final transaction = widget.editorState.transaction;
transaction.updateNode(node, {
blockComponentBackgroundColor: option.id,
});
await editorState.apply(transaction);
await widget.editorState.apply(transaction);

innerController.close();
controller.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,68 @@ class TurnIntoOptionAction extends CustomActionCell {
TurnIntoOptionAction({
required this.editorState,
required this.blockComponentBuilder,
required this.mutex,
});

final EditorState editorState;
final Map<String, BlockComponentBuilder> blockComponentBuilder;
final PopoverController innerController = PopoverController();
final PopoverMutex mutex;

@override
Widget buildWithContext(
BuildContext context,
PopoverController controller,
PopoverMutex? mutex,
) {
return TurnInfoButton(
editorState: editorState,
blockComponentBuilder: blockComponentBuilder,
mutex: this.mutex,
);
}
}

class TurnInfoButton extends StatefulWidget {
const TurnInfoButton({
super.key,
required this.editorState,
required this.blockComponentBuilder,
required this.mutex,
});

final EditorState editorState;
final Map<String, BlockComponentBuilder> blockComponentBuilder;
final PopoverMutex mutex;

@override
State<TurnInfoButton> createState() => _TurnInfoButtonState();
}

class _TurnInfoButtonState extends State<TurnInfoButton> {
final PopoverController innerController = PopoverController();
bool isOpen = false;

@override
Widget build(BuildContext context) {
return AppFlowyPopover(
asBarrier: true,
controller: innerController,
mutex: mutex,
popupBuilder: (context) => BlocProvider<BlockActionOptionCubit>(
create: (context) => BlockActionOptionCubit(
editorState: editorState,
blockComponentBuilder: blockComponentBuilder,
),
child: BlocBuilder<BlockActionOptionCubit, BlockActionOptionState>(
builder: (context, _) => _buildTurnIntoOptionMenu(context),
),
),
mutex: widget.mutex,
popupBuilder: (context) {
isOpen = true;
return BlocProvider<BlockActionOptionCubit>(
create: (context) => BlockActionOptionCubit(
editorState: widget.editorState,
blockComponentBuilder: widget.blockComponentBuilder,
),
child: BlocBuilder<BlockActionOptionCubit, BlockActionOptionState>(
builder: (context, _) => _buildTurnIntoOptionMenu(context),
),
);
},
onClose: () => isOpen = false,
direction: PopoverDirection.rightWithCenterAligned,
offset: const Offset(10, 0),
animationDuration: Durations.short3,
beginScaleFactor: 1.0,
beginOpacity: 0.8,
Expand All @@ -51,14 +86,16 @@ class TurnIntoOptionAction extends CustomActionCell {
leftIcon: const FlowySvg(FlowySvgs.turninto_s),
name: LocaleKeys.document_plugins_optionAction_turnInto.tr(),
onTap: () {
innerController.show();
if (!isOpen) {
innerController.show();
}
},
),
);
}

Widget _buildTurnIntoOptionMenu(BuildContext context) {
final selection = editorState.selection?.normalized;
final selection = widget.editorState.selection?.normalized;
// the selection may not be collapsed, for example, if a block contains some children,
// the selection will be the start from the current block and end at the last child block.
// we should take care of this case:
Expand All @@ -68,7 +105,7 @@ class TurnIntoOptionAction extends CustomActionCell {
return const SizedBox.shrink();
}

final node = editorState.getNodeAtPath(selection.start.path);
final node = widget.editorState.getNodeAtPath(selection.start.path);
if (node == null) {
return const SizedBox.shrink();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ final headingsToolbarItem = ToolbarItem(

if (type == HeadingBlockKeys.type) {
// from paragraph to heading
debugPrint('from paragraph to heading, newLevel: $newLevel');
final newNode = node.copyWith(
type: type,
attributes: {
Expand All @@ -85,7 +84,6 @@ final headingsToolbarItem = ToolbarItem(
await editorState.apply(transaction);
} else {
// from heading to paragraph
debugPrint('from heading to paragraph, newLevel: $newLevel');
await editorState.formatNode(
selection,
(node) => node.copyWith(
Expand Down

0 comments on commit 596b2fc

Please sign in to comment.