mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support align and upgrade appflowy_editor (#2712)
* feat: support align and upgrade appflowy_editor * chore: try to fix linux analyze error * fix: error after inserting callout block * feat: add inline board / grid plugin * feat: refactor insert_page * fix: ref view in document * chore: add asset name and description to option align type * fix: linux flutter analyze * chore: disable file export and log * fix: the window always back to center after relaunching * fix: potential data lost in nested list * feat: re-design login page * fix: can't remove background color * chore: rename bundle id and change the macos app to non sandbox app --------- Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
|
||||
import 'package:appflowy/plugins/document/application/doc_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-document2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart'
|
||||
show
|
||||
@ -31,11 +30,12 @@ class TransactionAdapter {
|
||||
final String documentId;
|
||||
|
||||
Future<void> apply(Transaction transaction, EditorState editorState) async {
|
||||
// Log.debug('transaction => ${transaction.toJson()}');
|
||||
final actions = transaction.operations
|
||||
.map((op) => op.toBlockAction(editorState))
|
||||
.whereNotNull()
|
||||
.expand((element) => element);
|
||||
Log.debug('actions => $actions');
|
||||
// Log.debug('actions => $actions');
|
||||
await documentService.applyAction(
|
||||
documentId: documentId,
|
||||
actions: actions,
|
||||
@ -85,6 +85,12 @@ extension on InsertOperation {
|
||||
..action = BlockActionTypePB.Insert
|
||||
..payload = payload,
|
||||
);
|
||||
if (node.children.isNotEmpty) {
|
||||
final childrenActions = node.children
|
||||
.map((e) => InsertOperation(e.path, [e]).toBlockAction(editorState))
|
||||
.expand((element) => element);
|
||||
actions.addAll(childrenActions);
|
||||
}
|
||||
previousNode = node;
|
||||
}
|
||||
return actions;
|
||||
|
@ -24,16 +24,6 @@ class AppFlowyEditorPage extends StatefulWidget {
|
||||
|
||||
class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
final scrollController = ScrollController();
|
||||
final slashMenuItems = [
|
||||
boardMenuItem,
|
||||
gridMenuItem,
|
||||
calloutItem,
|
||||
dividerMenuItem,
|
||||
mathEquationItem,
|
||||
codeBlockItem,
|
||||
emojiMenuItem,
|
||||
autoGeneratorMenuItem,
|
||||
];
|
||||
|
||||
final List<CommandShortcutEvent> commandShortcutEvents = [
|
||||
...codeBlockCommands,
|
||||
@ -53,6 +43,19 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
highlightColorItem,
|
||||
];
|
||||
|
||||
late final slashMenuItems = [
|
||||
dividerMenuItem,
|
||||
inlineGridMenuItem(documentBloc),
|
||||
referenceGridMenuItem,
|
||||
inlineBoardMenuItem(documentBloc),
|
||||
boardMenuItem,
|
||||
calloutItem,
|
||||
mathEquationItem,
|
||||
codeBlockItem,
|
||||
emojiMenuItem,
|
||||
autoGeneratorMenuItem,
|
||||
];
|
||||
|
||||
late final Map<String, BlockComponentBuilder> blockComponentBuilders =
|
||||
_customAppFlowyBlockComponentBuilders();
|
||||
late final List<CharacterShortcutEvent> characterShortcutEvents = [
|
||||
@ -170,7 +173,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
),
|
||||
textStyleBuilder: (level) => styleCustomizer.headingStyleBuilder(level),
|
||||
),
|
||||
ImageBlockKeys.type: ImageBlockComponentBuilder(),
|
||||
ImageBlockKeys.type: ImageBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
),
|
||||
BoardBlockKeys.type: BoardBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
),
|
||||
@ -225,14 +230,24 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
CalloutBlockKeys.type
|
||||
];
|
||||
|
||||
final supportAlignBuilderType = [
|
||||
ImageBlockKeys.type,
|
||||
];
|
||||
|
||||
final colorAction = [
|
||||
OptionAction.divider,
|
||||
OptionAction.color,
|
||||
];
|
||||
|
||||
final alignAction = [
|
||||
OptionAction.divider,
|
||||
OptionAction.align,
|
||||
];
|
||||
|
||||
final List<OptionAction> actions = [
|
||||
...standardActions,
|
||||
if (supportColorBuilderTypes.contains(entry.key)) ...colorAction,
|
||||
if (supportAlignBuilderType.contains(entry.key)) ...alignAction,
|
||||
];
|
||||
|
||||
builder.showActions = (_) => true;
|
||||
|
@ -24,14 +24,15 @@ class BlockOptionButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final popoverActions = actions.map((e) {
|
||||
if (e == OptionAction.divider) {
|
||||
return DividerOptionAction();
|
||||
} else if (e == OptionAction.color) {
|
||||
return ColorOptionAction(
|
||||
editorState: editorState,
|
||||
);
|
||||
} else {
|
||||
return OptionActionWrapper(e);
|
||||
switch (e) {
|
||||
case OptionAction.divider:
|
||||
return DividerOptionAction();
|
||||
case OptionAction.color:
|
||||
return ColorOptionAction(editorState: editorState);
|
||||
case OptionAction.align:
|
||||
return AlignOptionAction(editorState: editorState);
|
||||
default:
|
||||
return OptionActionWrapper(e);
|
||||
}
|
||||
}).toList();
|
||||
|
||||
@ -119,6 +120,7 @@ class BlockOptionButton extends StatelessWidget {
|
||||
case OptionAction.moveDown:
|
||||
transaction.moveNode(node.path.next.next, node);
|
||||
break;
|
||||
case OptionAction.align:
|
||||
case OptionAction.color:
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/select_option_editor.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide FlowySvg;
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@ -18,6 +18,90 @@ enum OptionAction {
|
||||
moveDown,
|
||||
color,
|
||||
divider,
|
||||
align;
|
||||
|
||||
String get assetName {
|
||||
switch (this) {
|
||||
case OptionAction.delete:
|
||||
return 'editor/delete';
|
||||
case OptionAction.duplicate:
|
||||
return 'editor/duplicate';
|
||||
case OptionAction.turnInto:
|
||||
return 'editor/turn_into';
|
||||
case OptionAction.moveUp:
|
||||
return 'editor/move_up';
|
||||
case OptionAction.moveDown:
|
||||
return 'editor/move_down';
|
||||
case OptionAction.color:
|
||||
return 'editor/color';
|
||||
case OptionAction.divider:
|
||||
return 'editor/divider';
|
||||
case OptionAction.align:
|
||||
return 'editor/align/center';
|
||||
}
|
||||
}
|
||||
|
||||
String get description {
|
||||
switch (this) {
|
||||
case OptionAction.delete:
|
||||
return LocaleKeys.document_plugins_optionAction_delete.tr();
|
||||
case OptionAction.duplicate:
|
||||
return LocaleKeys.document_plugins_optionAction_duplicate.tr();
|
||||
case OptionAction.turnInto:
|
||||
return LocaleKeys.document_plugins_optionAction_turnInto.tr();
|
||||
case OptionAction.moveUp:
|
||||
return LocaleKeys.document_plugins_optionAction_moveUp.tr();
|
||||
case OptionAction.moveDown:
|
||||
return LocaleKeys.document_plugins_optionAction_moveDown.tr();
|
||||
case OptionAction.color:
|
||||
return LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
case OptionAction.align:
|
||||
return LocaleKeys.document_plugins_optionAction_align.tr();
|
||||
case OptionAction.divider:
|
||||
throw UnsupportedError('Divider does not have description');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum OptionAlignType {
|
||||
left,
|
||||
center,
|
||||
right;
|
||||
|
||||
static OptionAlignType fromString(String? value) {
|
||||
switch (value) {
|
||||
case 'left':
|
||||
return OptionAlignType.left;
|
||||
case 'center':
|
||||
return OptionAlignType.center;
|
||||
case 'right':
|
||||
return OptionAlignType.right;
|
||||
default:
|
||||
return OptionAlignType.center;
|
||||
}
|
||||
}
|
||||
|
||||
String get assetName {
|
||||
switch (this) {
|
||||
case OptionAlignType.left:
|
||||
return 'editor/align/left';
|
||||
case OptionAlignType.center:
|
||||
return 'editor/align/center';
|
||||
case OptionAlignType.right:
|
||||
return 'editor/align/right';
|
||||
}
|
||||
}
|
||||
|
||||
String get description {
|
||||
switch (this) {
|
||||
case OptionAlignType.left:
|
||||
return LocaleKeys.document_plugins_optionAction_left.tr();
|
||||
case OptionAlignType.center:
|
||||
return LocaleKeys.document_plugins_optionAction_center.tr();
|
||||
case OptionAlignType.right:
|
||||
return LocaleKeys.document_plugins_optionAction_right.tr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DividerOptionAction extends CustomActionCell {
|
||||
@ -30,6 +114,98 @@ class DividerOptionAction extends CustomActionCell {
|
||||
}
|
||||
}
|
||||
|
||||
class AlignOptionAction extends PopoverActionCell {
|
||||
AlignOptionAction({
|
||||
required this.editorState,
|
||||
});
|
||||
|
||||
final EditorState editorState;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) {
|
||||
return FlowySvg(
|
||||
name: align.assetName,
|
||||
size: const Size.square(12),
|
||||
).padding(all: 2.0);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
return LocaleKeys.document_plugins_optionAction_align.tr();
|
||||
}
|
||||
|
||||
@override
|
||||
PopoverActionCellBuilder get builder =>
|
||||
(context, parentController, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final children = buildAlignOptions(context, (align) async {
|
||||
await onAlignChanged(align);
|
||||
controller.close();
|
||||
parentController.close();
|
||||
});
|
||||
return IntrinsicHeight(
|
||||
child: IntrinsicWidth(
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
List<Widget> buildAlignOptions(
|
||||
BuildContext context,
|
||||
void Function(OptionAlignType) onTap,
|
||||
) {
|
||||
return OptionAlignType.values.map((e) => OptionAlignWrapper(e)).map((e) {
|
||||
final leftIcon = e.leftIcon(Theme.of(context).colorScheme.onSurface);
|
||||
final rightIcon = e.rightIcon(Theme.of(context).colorScheme.onSurface);
|
||||
return HoverButton(
|
||||
onTap: () => onTap(e.inner),
|
||||
itemHeight: ActionListSizes.itemHeight,
|
||||
leftIcon: leftIcon,
|
||||
name: e.name,
|
||||
rightIcon: rightIcon,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
OptionAlignType get align {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return OptionAlignType.center;
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
final align = node?.attributes['align'];
|
||||
return OptionAlignType.fromString(align);
|
||||
}
|
||||
|
||||
Future<void> onAlignChanged(OptionAlignType align) async {
|
||||
if (align == this.align) {
|
||||
return;
|
||||
}
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
final transaction = editorState.transaction;
|
||||
transaction.updateNode(node, {
|
||||
'align': align.name,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorOptionAction extends PopoverActionCell {
|
||||
ColorOptionAction({
|
||||
required this.editorState,
|
||||
@ -46,60 +222,61 @@ class ColorOptionAction extends PopoverActionCell {
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
return LocaleKeys.toolbar_color.tr();
|
||||
}
|
||||
String get name => LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext context, PopoverController controller)
|
||||
get builder => (context, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final bgColor =
|
||||
node.attributes[blockComponentBackgroundColor] as String?;
|
||||
final selectedColor = convertHexToSelectOptionColorPB(
|
||||
bgColor,
|
||||
context,
|
||||
);
|
||||
|
||||
return SelectOptionColorList(
|
||||
selectedColor: selectedColor,
|
||||
onSelectedColor: (color) {
|
||||
controller.close();
|
||||
|
||||
final nodes = editorState.getNodesInSelection(selection);
|
||||
final transaction = editorState.transaction;
|
||||
for (final node in nodes) {
|
||||
transaction.updateNode(node, {
|
||||
blockComponentBackgroundColor:
|
||||
color.toColor(context).toHex(),
|
||||
});
|
||||
}
|
||||
editorState.apply(transaction);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
SelectOptionColorPB? convertHexToSelectOptionColorPB(
|
||||
String? hexColor,
|
||||
Widget Function(
|
||||
BuildContext context,
|
||||
) {
|
||||
if (hexColor == null) {
|
||||
return null;
|
||||
}
|
||||
for (final value in SelectOptionColorPB.values) {
|
||||
if (value.toColor(context).toHex() == hexColor) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
PopoverController parentController,
|
||||
PopoverController controller,
|
||||
) get builder => (context, parentController, controller) {
|
||||
final selection = editorState.selection?.normalized;
|
||||
if (selection == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
if (node == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final bgColor =
|
||||
node.attributes[blockComponentBackgroundColor] as String?;
|
||||
final selectedColor = bgColor?.toColor();
|
||||
|
||||
final colors = [
|
||||
// clear background color.
|
||||
FlowyColorOption(
|
||||
color: Colors.transparent,
|
||||
name: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
),
|
||||
...FlowyTint.values.map(
|
||||
(e) => FlowyColorOption(
|
||||
color: e.color(context),
|
||||
name: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
return FlowyColorPicker(
|
||||
colors: colors,
|
||||
selected: selectedColor,
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
width: 1,
|
||||
),
|
||||
onTap: (color, index) async {
|
||||
final transaction = editorState.transaction;
|
||||
final backgroundColor =
|
||||
color == Colors.transparent ? null : color.toHex();
|
||||
transaction.updateNode(node, {
|
||||
blockComponentBackgroundColor: backgroundColor,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
|
||||
controller.close();
|
||||
parentController.close();
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
class OptionActionWrapper extends ActionCell {
|
||||
@ -108,60 +285,20 @@ class OptionActionWrapper extends ActionCell {
|
||||
final OptionAction inner;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) {
|
||||
var name = '';
|
||||
// TODO: add icons.
|
||||
switch (inner) {
|
||||
case OptionAction.delete:
|
||||
name = 'editor/delete';
|
||||
break;
|
||||
case OptionAction.duplicate:
|
||||
name = 'editor/duplicate';
|
||||
break;
|
||||
case OptionAction.turnInto:
|
||||
name = 'editor/turn_into';
|
||||
break;
|
||||
case OptionAction.moveUp:
|
||||
name = 'editor/move_up';
|
||||
break;
|
||||
case OptionAction.moveDown:
|
||||
name = 'editor/move_down';
|
||||
break;
|
||||
default:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
if (name.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return FlowySvg(name: name);
|
||||
}
|
||||
Widget? leftIcon(Color iconColor) => FlowySvg(name: inner.assetName);
|
||||
|
||||
@override
|
||||
String get name {
|
||||
var description = '';
|
||||
switch (inner) {
|
||||
// TODO: l10n
|
||||
case OptionAction.delete:
|
||||
description = LocaleKeys.document_plugins_optionAction_delete.tr();
|
||||
break;
|
||||
case OptionAction.duplicate:
|
||||
description = LocaleKeys.document_plugins_optionAction_duplicate.tr();
|
||||
break;
|
||||
case OptionAction.turnInto:
|
||||
description = LocaleKeys.document_plugins_optionAction_turnInto.tr();
|
||||
break;
|
||||
case OptionAction.moveUp:
|
||||
description = LocaleKeys.document_plugins_optionAction_moveUp.tr();
|
||||
break;
|
||||
case OptionAction.moveDown:
|
||||
description = LocaleKeys.document_plugins_optionAction_moveDown.tr();
|
||||
break;
|
||||
case OptionAction.color:
|
||||
description = LocaleKeys.document_plugins_optionAction_color.tr();
|
||||
break;
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
String get name => inner.description;
|
||||
}
|
||||
|
||||
class OptionAlignWrapper extends ActionCell {
|
||||
OptionAlignWrapper(this.inner);
|
||||
|
||||
final OptionAlignType inner;
|
||||
|
||||
@override
|
||||
Widget? leftIcon(Color iconColor) => FlowySvg(name: inner.assetName);
|
||||
|
||||
@override
|
||||
String get name => inner.description;
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class OptionActionList extends StatelessWidget {
|
||||
case OptionAction.moveDown:
|
||||
transaction.moveNode(node.path.next.next, node);
|
||||
break;
|
||||
case OptionAction.align:
|
||||
case OptionAction.color:
|
||||
case OptionAction.divider:
|
||||
throw UnimplementedError();
|
||||
|
@ -15,7 +15,31 @@ class DatabaseBlockKeys {
|
||||
}
|
||||
|
||||
extension InsertDatabase on EditorState {
|
||||
Future<void> insertPage(ViewPB parentView, ViewPB childView) async {
|
||||
Future<void> insertInlinePage(String parentViewId, ViewPB childView) async {
|
||||
final selection = this.selection;
|
||||
if (selection == null || !selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
final node = getNodeAtPath(selection.end.path);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final transaction = this.transaction;
|
||||
transaction.insertNode(
|
||||
selection.end.path,
|
||||
Node(
|
||||
type: _convertPageType(childView),
|
||||
attributes: {
|
||||
DatabaseBlockKeys.parentID: parentViewId,
|
||||
DatabaseBlockKeys.viewID: childView.id,
|
||||
},
|
||||
),
|
||||
);
|
||||
await apply(transaction);
|
||||
}
|
||||
|
||||
Future<void> insertReferencePage(ViewPB childView) async {
|
||||
final selection = this.selection;
|
||||
if (selection == null || !selection.isCollapsed) {
|
||||
return;
|
||||
|
@ -35,7 +35,7 @@ void showLinkToPageMenu(
|
||||
layoutType: pageType,
|
||||
hintText: pageType.toHintText(),
|
||||
onSelected: (appPB, viewPB) {
|
||||
editorState.insertPage(appPB, viewPB);
|
||||
editorState.insertReferencePage(viewPB);
|
||||
linkToPageMenuEntry.remove();
|
||||
},
|
||||
),
|
||||
|
@ -7,7 +7,7 @@ import 'package:appflowy/plugins/document/application/prelude.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/insert_page_command.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem boardViewMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
name: LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
@ -15,43 +15,21 @@ SelectionMenuItem boardViewMenuItem(DocumentBloc documentBloc) =>
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['board', 'kanban'],
|
||||
keywords: ['board', 'kanban', 'database'],
|
||||
handler: (editorState, menuService, context) async {
|
||||
if (!documentBloc.view.hasParentViewId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final appId = documentBloc.view.parentViewId;
|
||||
final service = ViewBackendService();
|
||||
|
||||
final result = (await ViewBackendService.createView(
|
||||
parentViewId: appId,
|
||||
final parentViewId = documentBloc.view.parentViewId;
|
||||
ViewBackendService.createView(
|
||||
parentViewId: parentViewId,
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layoutType: ViewLayoutPB.Board,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
|
||||
// If the result is null, then something went wrong here.
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final app = (await service.getView(result.viewId)).getLeftOrNull();
|
||||
// We should show an error dialog.
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final view = (await service.getChildView(
|
||||
parentViewId: result.viewId,
|
||||
childViewId: result.id,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
// As this.
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorState.insertPage(app, view);
|
||||
).then(
|
||||
(value) => value
|
||||
.swap()
|
||||
.map((r) => editorState.insertInlinePage(parentViewId, r)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -51,7 +51,7 @@ SelectionMenuItem calloutItem = SelectionMenuItem.node(
|
||||
nodeBuilder: (editorState) => calloutNode(),
|
||||
replace: (_, node) => node.delta?.isEmpty ?? false,
|
||||
updateSelection: (_, path, __, ___) {
|
||||
return Selection.single(path: [...path, 0], startOffset: 0);
|
||||
return Selection.single(path: path, startOffset: 0);
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -6,14 +6,14 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
SelectionMenuItem gridMenuItem = SelectionMenuItem(
|
||||
SelectionMenuItem referenceGridMenuItem = SelectionMenuItem(
|
||||
name: LocaleKeys.document_plugins_referencedGrid.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
name: 'editor/board',
|
||||
name: 'editor/grid',
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['referenced', 'grid'],
|
||||
keywords: ['referenced', 'grid', 'database'],
|
||||
handler: (editorState, menuService, context) {
|
||||
final container = Overlay.of(context);
|
||||
showLinkToPageMenu(
|
||||
|
@ -7,7 +7,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
SelectionMenuItem gridViewMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
|
||||
SelectionMenuItem(
|
||||
name: LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
|
||||
icon: (editorState, onSelected, style) => SelectableSvgWidget(
|
||||
@ -15,43 +15,22 @@ SelectionMenuItem gridViewMenuItem(DocumentBloc documentBloc) =>
|
||||
isSelected: onSelected,
|
||||
style: style,
|
||||
),
|
||||
keywords: ['grid'],
|
||||
keywords: ['grid', 'database'],
|
||||
handler: (editorState, menuService, context) async {
|
||||
if (!documentBloc.view.hasParentViewId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final appId = documentBloc.view.parentViewId;
|
||||
final service = ViewBackendService();
|
||||
|
||||
final result = (await ViewBackendService.createView(
|
||||
parentViewId: appId,
|
||||
final parentViewId = documentBloc.view.parentViewId;
|
||||
ViewBackendService.createView(
|
||||
parentViewId: parentViewId,
|
||||
openAfterCreate: false,
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layoutType: ViewLayoutPB.Grid,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
|
||||
// If the result is null, then something went wrong here.
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final app = (await service.getView(result.viewId)).getLeftOrNull();
|
||||
// We should show an error dialog.
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final view = (await service.getChildView(
|
||||
parentViewId: result.viewId,
|
||||
childViewId: result.id,
|
||||
))
|
||||
.getLeftOrNull();
|
||||
// As this.
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorState.insertPage(app, view);
|
||||
).then(
|
||||
(value) => value
|
||||
.swap()
|
||||
.map((r) => editorState.insertInlinePage(parentViewId, r)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
Reference in New Issue
Block a user