mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-25 22:23:44 +00:00
feat: support plus menu in table cell on mobile (#7048)
* feat: support plus menu in table cell on mobile * test: support plus menu in table cell on mobile * feat: add lightImpact feedback * chore: optimize the action sheet
This commit is contained in:
parent
802a667907
commit
83e50d376e
@ -385,5 +385,56 @@ void main() {
|
||||
expect(paragraph.delta!, isEmpty);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('''
|
||||
1. insert a simple table via + menu
|
||||
2. insert a heading block in table cell
|
||||
''', (tester) async {
|
||||
await tester.launchInAnonymousMode();
|
||||
await tester.createNewDocumentOnMobile('simple table');
|
||||
|
||||
final editorState = tester.editor.getCurrentEditorState();
|
||||
// focus on the editor
|
||||
unawaited(
|
||||
editorState.updateSelectionWithReason(
|
||||
Selection.collapsed(Position(path: [0])),
|
||||
reason: SelectionUpdateReason.uiEvent,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final firstParagraphPath = [0, 0, 0, 0];
|
||||
|
||||
// open the plus menu and select the table block
|
||||
{
|
||||
await tester.openPlusMenuAndClickButton(
|
||||
LocaleKeys.document_slashMenu_name_table.tr(),
|
||||
);
|
||||
|
||||
// check the block is inserted
|
||||
final table = editorState.getNodeAtPath([0])!;
|
||||
expect(table.type, equals(SimpleTableBlockKeys.type));
|
||||
expect(table.rowLength, equals(2));
|
||||
expect(table.columnLength, equals(2));
|
||||
|
||||
// focus on the first cell
|
||||
|
||||
final selection = editorState.selection!;
|
||||
expect(selection.isCollapsed, isTrue);
|
||||
expect(selection.start.path, equals(firstParagraphPath));
|
||||
}
|
||||
|
||||
// open the plus menu and select the heading block
|
||||
{
|
||||
await tester.openPlusMenuAndClickButton(
|
||||
LocaleKeys.editor_toggleHeading1ShortForm.tr(),
|
||||
);
|
||||
|
||||
// check the heading block is inserted
|
||||
final heading = editorState.getNodeAtPath([0, 0, 0, 0])!;
|
||||
expect(heading.type, equals(HeadingBlockKeys.type));
|
||||
expect(heading.level, equals(1));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -138,7 +138,6 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
||||
),
|
||||
_divider(),
|
||||
..._buildPublishActions(context),
|
||||
_divider(),
|
||||
MobileQuickActionButton(
|
||||
text: LocaleKeys.button_delete.tr(),
|
||||
textColor: Theme.of(context).colorScheme.error,
|
||||
@ -191,6 +190,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
||||
MobileViewBottomSheetBodyAction.unpublish,
|
||||
),
|
||||
),
|
||||
_divider(),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
@ -201,6 +201,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
||||
MobileViewBottomSheetBodyAction.publish,
|
||||
),
|
||||
),
|
||||
_divider(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,7 +675,12 @@ CalloutBlockComponentBuilder _buildCalloutBlockComponentBuilder(
|
||||
final calloutBGColor = AFThemeExtension.of(context).calloutBGColor;
|
||||
return CalloutBlockComponentBuilder(
|
||||
configuration: configuration.copyWith(
|
||||
padding: (node) => const EdgeInsets.symmetric(vertical: 10),
|
||||
padding: (node) {
|
||||
if (UniversalPlatform.isMobile) {
|
||||
return configuration.padding(node);
|
||||
}
|
||||
return const EdgeInsets.symmetric(vertical: 10);
|
||||
},
|
||||
textAlign: (node) => _buildTextAlignInTableCell(
|
||||
context,
|
||||
node: node,
|
||||
@ -725,6 +730,7 @@ CodeBlockComponentBuilder _buildCodeBlockComponentBuilder(
|
||||
) {
|
||||
return CodeBlockComponentBuilder(
|
||||
styleBuilder: styleCustomizer.codeBlockStyleBuilder,
|
||||
configuration: configuration,
|
||||
padding: const EdgeInsets.only(left: 20, right: 30, bottom: 34),
|
||||
languagePickerBuilder: codeBlockLanguagePickerBuilder,
|
||||
copyButtonBuilder: codeBlockCopyBuilder,
|
||||
@ -763,9 +769,10 @@ ToggleListBlockComponentBuilder _buildToggleListBlockComponentBuilder(
|
||||
final factor = pageStyle.fontLayout.factor;
|
||||
final headingPaddings =
|
||||
pageStyle.lineHeightLayout.headingPaddings.map((e) => e * factor);
|
||||
int level = node.attributes[HeadingBlockKeys.level] ?? 6;
|
||||
level = level.clamp(1, 6);
|
||||
return EdgeInsets.only(top: headingPaddings.elementAt(level - 1));
|
||||
final level =
|
||||
(node.attributes[HeadingBlockKeys.level] ?? 6).clamp(1, 6);
|
||||
final top = headingPaddings.elementAt(level - 1);
|
||||
return configuration.padding(node).copyWith(top: top);
|
||||
}
|
||||
|
||||
return const EdgeInsets.only(top: 12.0, bottom: 4.0);
|
||||
@ -846,7 +853,9 @@ FileBlockComponentBuilder _buildFileBlockComponentBuilder(
|
||||
BuildContext context,
|
||||
BlockComponentConfiguration configuration,
|
||||
) {
|
||||
return FileBlockComponentBuilder(configuration: configuration);
|
||||
return FileBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
);
|
||||
}
|
||||
|
||||
SubPageBlockComponentBuilder _buildSubPageBlockComponentBuilder(
|
||||
|
||||
@ -281,9 +281,13 @@ class FileBlockComponentState extends State<FileBlockComponent>
|
||||
listenable: editorState.selectionNotifier,
|
||||
blockColor: editorState.editorStyle.selectionColor,
|
||||
supportTypes: const [BlockSelectionType.block],
|
||||
child: Padding(key: fileKey, padding: padding, child: child),
|
||||
child: Padding(
|
||||
key: fileKey,
|
||||
padding: padding,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
} else if (url == null || url.isEmpty) {
|
||||
} else {
|
||||
return Padding(
|
||||
key: fileKey,
|
||||
padding: padding,
|
||||
@ -384,6 +388,9 @@ class FileBlockComponentState extends State<FileBlockComponent>
|
||||
),
|
||||
const HSpace(8),
|
||||
],
|
||||
if (UniversalPlatform.isMobile) ...[
|
||||
const HSpace(36),
|
||||
],
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
|
||||
@ -0,0 +1,480 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/type_option_menu_item.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/multi_image_placeholder.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mobile_page_selector_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_item/mobile_add_block_toolbar_item.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/startup/tasks/app_widget.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class AddBlockMenuItemBuilder {
|
||||
AddBlockMenuItemBuilder({
|
||||
required this.editorState,
|
||||
required this.selection,
|
||||
});
|
||||
|
||||
final EditorState editorState;
|
||||
final Selection selection;
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> buildTypeOptionMenuItemValues(
|
||||
BuildContext context,
|
||||
) {
|
||||
if (selection.isCollapsed) {
|
||||
final node = editorState.getNodeAtPath(selection.end.path);
|
||||
if (node?.parentTableCellNode != null) {
|
||||
return _buildTableTypeOptionMenuItemValues(context);
|
||||
}
|
||||
}
|
||||
return _buildDefaultTypeOptionMenuItemValues(context);
|
||||
}
|
||||
|
||||
/// Build the default type option menu item values.
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildDefaultTypeOptionMenuItemValues(
|
||||
BuildContext context,
|
||||
) {
|
||||
final colorMap = _colorMap(context);
|
||||
return [
|
||||
..._buildHeadingMenuItems(colorMap),
|
||||
..._buildParagraphMenuItems(colorMap),
|
||||
..._buildTodoListMenuItems(colorMap),
|
||||
..._buildTableMenuItems(colorMap),
|
||||
..._buildQuoteMenuItems(colorMap),
|
||||
..._buildListMenuItems(colorMap),
|
||||
..._buildToggleHeadingMenuItems(colorMap),
|
||||
..._buildImageMenuItems(colorMap),
|
||||
..._buildPhotoGalleryMenuItems(colorMap),
|
||||
..._buildFileMenuItems(colorMap),
|
||||
..._buildMentionMenuItems(context, colorMap),
|
||||
..._buildDividerMenuItems(colorMap),
|
||||
..._buildCalloutMenuItems(colorMap),
|
||||
..._buildCodeMenuItems(colorMap),
|
||||
..._buildMathEquationMenuItems(colorMap),
|
||||
];
|
||||
}
|
||||
|
||||
/// Build the table type option menu item values.
|
||||
List<TypeOptionMenuItemValue<String>> _buildTableTypeOptionMenuItemValues(
|
||||
BuildContext context,
|
||||
) {
|
||||
final colorMap = _colorMap(context);
|
||||
return [
|
||||
..._buildHeadingMenuItems(colorMap),
|
||||
..._buildParagraphMenuItems(colorMap),
|
||||
..._buildTodoListMenuItems(colorMap),
|
||||
..._buildQuoteMenuItems(colorMap),
|
||||
..._buildListMenuItems(colorMap),
|
||||
..._buildToggleHeadingMenuItems(colorMap),
|
||||
..._buildImageMenuItems(colorMap),
|
||||
..._buildFileMenuItems(colorMap),
|
||||
..._buildMentionMenuItems(context, colorMap),
|
||||
..._buildDividerMenuItems(colorMap),
|
||||
..._buildCalloutMenuItems(colorMap),
|
||||
..._buildCodeMenuItems(colorMap),
|
||||
..._buildMathEquationMenuItems(colorMap),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildHeadingMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading1.tr(),
|
||||
icon: FlowySvgs.m_add_block_h1_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 1)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading2.tr(),
|
||||
icon: FlowySvgs.m_add_block_h2_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 2)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading3.tr(),
|
||||
icon: FlowySvgs.m_add_block_h3_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 3)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildParagraphMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[ParagraphBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_text.tr(),
|
||||
icon: FlowySvgs.m_add_block_paragraph_s,
|
||||
onTap: (_, __) => _insertBlock(paragraphNode()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildTodoListMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: TodoListBlockKeys.type,
|
||||
backgroundColor: colorMap[TodoListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_checkbox.tr(),
|
||||
icon: FlowySvgs.m_add_block_checkbox_s,
|
||||
onTap: (_, __) => _insertBlock(todoListNode(checked: false)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildTableMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: SimpleTableBlockKeys.type,
|
||||
backgroundColor: colorMap[SimpleTableBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_table.tr(),
|
||||
icon: FlowySvgs.slash_menu_icon_simple_table_s,
|
||||
onTap: (_, __) => _insertBlock(
|
||||
createSimpleTableBlockNode(columnCount: 2, rowCount: 2),
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildQuoteMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: QuoteBlockKeys.type,
|
||||
backgroundColor: colorMap[QuoteBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_quote.tr(),
|
||||
icon: FlowySvgs.m_add_block_quote_s,
|
||||
onTap: (_, __) => _insertBlock(quoteNode()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildListMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
// bulleted list, numbered list, toggle list
|
||||
TypeOptionMenuItemValue(
|
||||
value: BulletedListBlockKeys.type,
|
||||
backgroundColor: colorMap[BulletedListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_bulletedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_bulleted_list_s,
|
||||
onTap: (_, __) => _insertBlock(bulletedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: NumberedListBlockKeys.type,
|
||||
backgroundColor: colorMap[NumberedListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_numberedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_numbered_list_s,
|
||||
onTap: (_, __) => _insertBlock(numberedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_toggle_s,
|
||||
onTap: (_, __) => _insertBlock(toggleListBlockNode()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildToggleHeadingMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading1ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading1_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading2ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading2_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode(level: 2)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading3ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading3_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode(level: 3)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildImageMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: ImageBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_image.tr(),
|
||||
icon: FlowySvgs.m_add_block_image_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
|
||||
await editorState.insertEmptyImageBlock(imagePlaceholderKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildPhotoGalleryMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: MultiImageBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_photoGallery_name.tr(),
|
||||
icon: FlowySvgs.m_add_block_photo_gallery_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final imagePlaceholderKey = GlobalKey<MultiImagePlaceholderState>();
|
||||
await editorState.insertEmptyMultiImageBlock(imagePlaceholderKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildFileMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: FileBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_file_name.tr(),
|
||||
icon: FlowySvgs.media_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final fileGlobalKey = GlobalKey<FileBlockComponentState>();
|
||||
await editorState.insertEmptyFileBlock(fileGlobalKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildMentionMenuItems(
|
||||
BuildContext context,
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[MentionBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_date.tr(),
|
||||
icon: FlowySvgs.m_add_block_date_s,
|
||||
onTap: (_, __) => _insertBlock(dateMentionNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[MentionBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_page.tr(),
|
||||
icon: FlowySvgs.icon_document_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
|
||||
final currentViewId = getIt<MenuSharedState>().latestOpenView?.id;
|
||||
final view = await showPageSelectorSheet(
|
||||
context,
|
||||
currentViewId: currentViewId,
|
||||
);
|
||||
|
||||
if (view != null) {
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertBlockAfterCurrentSelection(
|
||||
selection,
|
||||
pageMentionNode(view.id),
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildDividerMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: DividerBlockKeys.type,
|
||||
backgroundColor: colorMap[DividerBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_divider.tr(),
|
||||
icon: FlowySvgs.m_add_block_divider_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertDivider(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
// callout, code, math equation
|
||||
List<TypeOptionMenuItemValue<String>> _buildCalloutMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: CalloutBlockKeys.type,
|
||||
backgroundColor: colorMap[CalloutBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_callout.tr(),
|
||||
icon: FlowySvgs.m_add_block_callout_s,
|
||||
onTap: (_, __) => _insertBlock(calloutNode()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildCodeMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: CodeBlockKeys.type,
|
||||
backgroundColor: colorMap[CodeBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_codeBlockShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_code_s,
|
||||
onTap: (_, __) => _insertBlock(codeBlockNode()),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> _buildMathEquationMenuItems(
|
||||
Map<String, Color> colorMap,
|
||||
) {
|
||||
return [
|
||||
TypeOptionMenuItemValue(
|
||||
value: MathEquationBlockKeys.type,
|
||||
backgroundColor: colorMap[MathEquationBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_mathEquationShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_formula_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertMathEquation(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Map<String, Color> _colorMap(BuildContext context) {
|
||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||
if (isDarkMode) {
|
||||
return {
|
||||
HeadingBlockKeys.type: const Color(0xFF5465A1),
|
||||
ParagraphBlockKeys.type: const Color(0xFF5465A1),
|
||||
TodoListBlockKeys.type: const Color(0xFF4BB299),
|
||||
SimpleTableBlockKeys.type: const Color(0xFF4BB299),
|
||||
QuoteBlockKeys.type: const Color(0xFFBAAC74),
|
||||
BulletedListBlockKeys.type: const Color(0xFFA35F94),
|
||||
NumberedListBlockKeys.type: const Color(0xFFA35F94),
|
||||
ToggleListBlockKeys.type: const Color(0xFFA35F94),
|
||||
ImageBlockKeys.type: const Color(0xFFBAAC74),
|
||||
MentionBlockKeys.type: const Color(0xFF40AAB8),
|
||||
DividerBlockKeys.type: const Color(0xFF4BB299),
|
||||
CalloutBlockKeys.type: const Color(0xFF66599B),
|
||||
CodeBlockKeys.type: const Color(0xFF66599B),
|
||||
MathEquationBlockKeys.type: const Color(0xFF66599B),
|
||||
};
|
||||
}
|
||||
return {
|
||||
HeadingBlockKeys.type: const Color(0xFFBECCFF),
|
||||
ParagraphBlockKeys.type: const Color(0xFFBECCFF),
|
||||
TodoListBlockKeys.type: const Color(0xFF98F4CD),
|
||||
SimpleTableBlockKeys.type: const Color(0xFF98F4CD),
|
||||
QuoteBlockKeys.type: const Color(0xFFFDEDA7),
|
||||
BulletedListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
NumberedListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
ToggleListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
ImageBlockKeys.type: const Color(0xFFFDEDA7),
|
||||
MentionBlockKeys.type: const Color(0xFF91EAF5),
|
||||
DividerBlockKeys.type: const Color(0xFF98F4CD),
|
||||
CalloutBlockKeys.type: const Color(0xFFCABDFF),
|
||||
CodeBlockKeys.type: const Color(0xFFCABDFF),
|
||||
MathEquationBlockKeys.type: const Color(0xFFCABDFF),
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _insertBlock(Node node) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
() async {
|
||||
// if current selected block is a empty paragraph block, replace it with the new block.
|
||||
if (selection.isCollapsed) {
|
||||
final currentNode = editorState.getNodeAtPath(selection.end.path);
|
||||
final text = currentNode?.delta?.toPlainText();
|
||||
if (currentNode != null &&
|
||||
currentNode.type == ParagraphBlockKeys.type &&
|
||||
text != null &&
|
||||
text.isEmpty) {
|
||||
final transaction = editorState.transaction;
|
||||
transaction.insertNode(
|
||||
selection.end.path.next,
|
||||
node,
|
||||
);
|
||||
transaction.deleteNode(currentNode);
|
||||
if (node.type == SimpleTableBlockKeys.type) {
|
||||
transaction.afterSelection = Selection.collapsed(
|
||||
Position(
|
||||
// table -> row -> cell -> paragraph
|
||||
path: selection.end.path + [0, 0, 0],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
transaction.afterSelection = Selection.collapsed(
|
||||
Position(path: selection.end.path),
|
||||
);
|
||||
}
|
||||
transaction.selectionExtraInfo = {};
|
||||
await editorState.apply(transaction);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await editorState.insertBlockAfterCurrentSelection(selection, node);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4,21 +4,14 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/type_option_menu_item.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/multi_image_block_component/multi_image_placeholder.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mobile_page_selector_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_item/mobile_add_block_toolbar_item.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/startup/tasks/app_widget.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'add_block_menu_item_builder.dart';
|
||||
|
||||
@visibleForTesting
|
||||
const addBlockToolbarItemKey = ValueKey('add_block_toolbar_item');
|
||||
@ -94,323 +87,13 @@ class AddBlockMenu extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final builder = AddBlockMenuItemBuilder(
|
||||
editorState: editorState,
|
||||
selection: selection,
|
||||
);
|
||||
return TypeOptionMenu<String>(
|
||||
values: buildTypeOptionMenuItemValues(context),
|
||||
values: builder.buildTypeOptionMenuItemValues(context),
|
||||
scaleFactor: context.scale,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _insertBlock(Node node) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
() async {
|
||||
// if current selected block is a empty paragraph block, replace it with the new block.
|
||||
if (selection.isCollapsed) {
|
||||
final currentNode = editorState.getNodeAtPath(selection.end.path);
|
||||
final text = currentNode?.delta?.toPlainText();
|
||||
if (currentNode != null &&
|
||||
currentNode.type == ParagraphBlockKeys.type &&
|
||||
text != null &&
|
||||
text.isEmpty) {
|
||||
final transaction = editorState.transaction;
|
||||
transaction.insertNode(
|
||||
selection.end.path.next,
|
||||
node,
|
||||
);
|
||||
transaction.deleteNode(currentNode);
|
||||
if (node.type == SimpleTableBlockKeys.type) {
|
||||
transaction.afterSelection = Selection.collapsed(
|
||||
Position(
|
||||
// table -> row -> cell -> paragraph
|
||||
path: selection.end.path + [0, 0, 0],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
transaction.afterSelection = Selection.collapsed(
|
||||
Position(path: selection.end.path),
|
||||
);
|
||||
}
|
||||
transaction.selectionExtraInfo = {};
|
||||
await editorState.apply(transaction);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await editorState.insertBlockAfterCurrentSelection(selection, node);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<TypeOptionMenuItemValue<String>> buildTypeOptionMenuItemValues(
|
||||
BuildContext context,
|
||||
) {
|
||||
final colorMap = _colorMap(context);
|
||||
return [
|
||||
// heading 1 - 3
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading1.tr(),
|
||||
icon: FlowySvgs.m_add_block_h1_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 1)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading2.tr(),
|
||||
icon: FlowySvgs.m_add_block_h2_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 2)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: HeadingBlockKeys.type,
|
||||
backgroundColor: colorMap[HeadingBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_heading3.tr(),
|
||||
icon: FlowySvgs.m_add_block_h3_s,
|
||||
onTap: (_, __) => _insertBlock(headingNode(level: 3)),
|
||||
),
|
||||
|
||||
// paragraph
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[ParagraphBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_text.tr(),
|
||||
icon: FlowySvgs.m_add_block_paragraph_s,
|
||||
onTap: (_, __) => _insertBlock(paragraphNode()),
|
||||
),
|
||||
|
||||
// checkbox
|
||||
TypeOptionMenuItemValue(
|
||||
value: TodoListBlockKeys.type,
|
||||
backgroundColor: colorMap[TodoListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_checkbox.tr(),
|
||||
icon: FlowySvgs.m_add_block_checkbox_s,
|
||||
onTap: (_, __) => _insertBlock(todoListNode(checked: false)),
|
||||
),
|
||||
|
||||
// table
|
||||
TypeOptionMenuItemValue(
|
||||
value: SimpleTableBlockKeys.type,
|
||||
backgroundColor: colorMap[SimpleTableBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_table.tr(),
|
||||
icon: FlowySvgs.slash_menu_icon_simple_table_s,
|
||||
onTap: (_, __) => _insertBlock(
|
||||
createSimpleTableBlockNode(columnCount: 2, rowCount: 2),
|
||||
),
|
||||
),
|
||||
|
||||
// quote
|
||||
TypeOptionMenuItemValue(
|
||||
value: QuoteBlockKeys.type,
|
||||
backgroundColor: colorMap[QuoteBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_quote.tr(),
|
||||
icon: FlowySvgs.m_add_block_quote_s,
|
||||
onTap: (_, __) => _insertBlock(quoteNode()),
|
||||
),
|
||||
|
||||
// bulleted list, numbered list, toggle list
|
||||
TypeOptionMenuItemValue(
|
||||
value: BulletedListBlockKeys.type,
|
||||
backgroundColor: colorMap[BulletedListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_bulletedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_bulleted_list_s,
|
||||
onTap: (_, __) => _insertBlock(bulletedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: NumberedListBlockKeys.type,
|
||||
backgroundColor: colorMap[NumberedListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_numberedListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_numbered_list_s,
|
||||
onTap: (_, __) => _insertBlock(numberedListNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleListShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_toggle_s,
|
||||
onTap: (_, __) => _insertBlock(toggleListBlockNode()),
|
||||
),
|
||||
|
||||
// toggle headings
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading1ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading1_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading2ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading2_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode(level: 2)),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: ToggleListBlockKeys.type,
|
||||
backgroundColor: colorMap[ToggleListBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_toggleHeading3ShortForm.tr(),
|
||||
icon: FlowySvgs.toggle_heading3_s,
|
||||
iconPadding: const EdgeInsets.all(3),
|
||||
onTap: (_, __) => _insertBlock(toggleHeadingNode(level: 3)),
|
||||
),
|
||||
|
||||
// image
|
||||
TypeOptionMenuItemValue(
|
||||
value: ImageBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_image.tr(),
|
||||
icon: FlowySvgs.m_add_block_image_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
|
||||
await editorState.insertEmptyImageBlock(imagePlaceholderKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: MultiImageBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_photoGallery_name.tr(),
|
||||
icon: FlowySvgs.m_add_block_photo_gallery_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final imagePlaceholderKey = GlobalKey<MultiImagePlaceholderState>();
|
||||
await editorState.insertEmptyMultiImageBlock(imagePlaceholderKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: FileBlockKeys.type,
|
||||
backgroundColor: colorMap[ImageBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_file_name.tr(),
|
||||
icon: FlowySvgs.media_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 400), () async {
|
||||
final fileGlobalKey = GlobalKey<FileBlockComponentState>();
|
||||
await editorState.insertEmptyFileBlock(fileGlobalKey);
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// date
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[MentionBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_date.tr(),
|
||||
icon: FlowySvgs.m_add_block_date_s,
|
||||
onTap: (_, __) => _insertBlock(dateMentionNode()),
|
||||
),
|
||||
// page
|
||||
TypeOptionMenuItemValue(
|
||||
value: ParagraphBlockKeys.type,
|
||||
backgroundColor: colorMap[MentionBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_page.tr(),
|
||||
icon: FlowySvgs.icon_document_s,
|
||||
onTap: (_, __) async {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
|
||||
final currentViewId = getIt<MenuSharedState>().latestOpenView?.id;
|
||||
final view = await showPageSelectorSheet(
|
||||
context,
|
||||
currentViewId: currentViewId,
|
||||
);
|
||||
|
||||
if (view != null) {
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertBlockAfterCurrentSelection(
|
||||
selection,
|
||||
pageMentionNode(view.id),
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
// divider
|
||||
TypeOptionMenuItemValue(
|
||||
value: DividerBlockKeys.type,
|
||||
backgroundColor: colorMap[DividerBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_divider.tr(),
|
||||
icon: FlowySvgs.m_add_block_divider_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertDivider(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// callout, code, math equation
|
||||
TypeOptionMenuItemValue(
|
||||
value: CalloutBlockKeys.type,
|
||||
backgroundColor: colorMap[CalloutBlockKeys.type]!,
|
||||
text: LocaleKeys.document_plugins_callout.tr(),
|
||||
icon: FlowySvgs.m_add_block_callout_s,
|
||||
onTap: (_, __) => _insertBlock(calloutNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: CodeBlockKeys.type,
|
||||
backgroundColor: colorMap[CodeBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_codeBlockShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_code_s,
|
||||
onTap: (_, __) => _insertBlock(codeBlockNode()),
|
||||
),
|
||||
TypeOptionMenuItemValue(
|
||||
value: MathEquationBlockKeys.type,
|
||||
backgroundColor: colorMap[MathEquationBlockKeys.type]!,
|
||||
text: LocaleKeys.editor_mathEquationShortForm.tr(),
|
||||
icon: FlowySvgs.m_add_block_formula_s,
|
||||
onTap: (_, __) {
|
||||
AppGlobals.rootNavKey.currentContext?.pop(true);
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
editorState.insertMathEquation(selection);
|
||||
});
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Map<String, Color> _colorMap(BuildContext context) {
|
||||
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||
if (isDarkMode) {
|
||||
return {
|
||||
HeadingBlockKeys.type: const Color(0xFF5465A1),
|
||||
ParagraphBlockKeys.type: const Color(0xFF5465A1),
|
||||
TodoListBlockKeys.type: const Color(0xFF4BB299),
|
||||
SimpleTableBlockKeys.type: const Color(0xFF4BB299),
|
||||
QuoteBlockKeys.type: const Color(0xFFBAAC74),
|
||||
BulletedListBlockKeys.type: const Color(0xFFA35F94),
|
||||
NumberedListBlockKeys.type: const Color(0xFFA35F94),
|
||||
ToggleListBlockKeys.type: const Color(0xFFA35F94),
|
||||
ImageBlockKeys.type: const Color(0xFFBAAC74),
|
||||
MentionBlockKeys.type: const Color(0xFF40AAB8),
|
||||
DividerBlockKeys.type: const Color(0xFF4BB299),
|
||||
CalloutBlockKeys.type: const Color(0xFF66599B),
|
||||
CodeBlockKeys.type: const Color(0xFF66599B),
|
||||
MathEquationBlockKeys.type: const Color(0xFF66599B),
|
||||
};
|
||||
}
|
||||
return {
|
||||
HeadingBlockKeys.type: const Color(0xFFBECCFF),
|
||||
ParagraphBlockKeys.type: const Color(0xFFBECCFF),
|
||||
TodoListBlockKeys.type: const Color(0xFF98F4CD),
|
||||
SimpleTableBlockKeys.type: const Color(0xFF98F4CD),
|
||||
QuoteBlockKeys.type: const Color(0xFFFDEDA7),
|
||||
BulletedListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
NumberedListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
ToggleListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||
ImageBlockKeys.type: const Color(0xFFFDEDA7),
|
||||
MentionBlockKeys.type: const Color(0xFF91EAF5),
|
||||
DividerBlockKeys.type: const Color(0xFF98F4CD),
|
||||
CalloutBlockKeys.type: const Color(0xFFCABDFF),
|
||||
CodeBlockKeys.type: const Color(0xFFCABDFF),
|
||||
MathEquationBlockKeys.type: const Color(0xFFCABDFF),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.da
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
@ -546,9 +547,17 @@ class SimpleTableCellBlockWidgetState extends State<SimpleTableCellBlockWidget>
|
||||
isReorderingHitCellNotifier.value = isHitCurrentCell;
|
||||
if (isHitCurrentCell) {
|
||||
if (isReorderingColumn) {
|
||||
simpleTableContext.isReorderingHitIndex.value = node.columnIndex;
|
||||
if (simpleTableContext.isReorderingHitIndex.value != node.columnIndex) {
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
simpleTableContext.isReorderingHitIndex.value = node.columnIndex;
|
||||
}
|
||||
} else if (isReorderingRow) {
|
||||
simpleTableContext.isReorderingHitIndex.value = node.rowIndex;
|
||||
if (simpleTableContext.isReorderingHitIndex.value != node.rowIndex) {
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
simpleTableContext.isReorderingHitIndex.value = node.rowIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/simple_tab
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/simple_table/simple_table_widgets/simple_table_feedback.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class SimpleTableMobileDraggableReorderButton extends StatelessWidget {
|
||||
@ -46,6 +47,8 @@ class SimpleTableMobileDraggableReorderButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _startDragging() {
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
isShowingMenu.value = true;
|
||||
editorState.selection = null;
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ class _SimpleTableFeedbackState extends State<SimpleTableFeedback> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: Provider.value(
|
||||
value: widget.editorState,
|
||||
child: SimpleTableWidget(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user