mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: mobile UI regression (#4754)
* fix: aa menu item selected status * feat: support selecting word on iOS throught long pressing * chore: update editor version * feat: update add block menu colors * feat: add scrollbar in bottom sheet * fix: aa menu should not dimiss after changing block type * fix: add link menu ui issues * feat: sync bius status * Update frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar_item.dart Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> * chore: update editor version * fix: flutter analyze --------- Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
parent
26f8397624
commit
980bebf86a
@ -127,9 +127,11 @@ Future<T?> showMobileBottomSheet<T>(
|
|||||||
children: [
|
children: [
|
||||||
...children,
|
...children,
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: Scrollbar(
|
||||||
controller: scrollController,
|
child: SingleChildScrollView(
|
||||||
child: child,
|
controller: scrollController,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_date_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_date_block.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
enum MentionType {
|
enum MentionType {
|
||||||
|
@ -141,7 +141,7 @@ class EditorMigration {
|
|||||||
}
|
}
|
||||||
const backgroundColor = 'backgroundColor';
|
const backgroundColor = 'backgroundColor';
|
||||||
if (attributes.containsKey(backgroundColor)) {
|
if (attributes.containsKey(backgroundColor)) {
|
||||||
attributes[AppFlowyRichTextKeys.highlightColor] =
|
attributes[AppFlowyRichTextKeys.backgroundColor] =
|
||||||
attributes[backgroundColor];
|
attributes[backgroundColor];
|
||||||
attributes.remove(backgroundColor);
|
attributes.remove(backgroundColor);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ Future<T?> showEditLinkBottomSheet<T>(
|
|||||||
return showMobileBottomSheet(
|
return showMobileBottomSheet(
|
||||||
context,
|
context,
|
||||||
showHeader: false,
|
showHeader: false,
|
||||||
|
showCloseButton: false,
|
||||||
|
showDragHandle: true,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return MobileBottomSheetEditLinkWidget(
|
return MobileBottomSheetEditLinkWidget(
|
||||||
text: text,
|
text: text,
|
||||||
|
@ -71,7 +71,8 @@ class BIUSItems extends StatelessWidget {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
icon: icon,
|
icon: icon,
|
||||||
isSelected: editorState.isTextDecorationSelected(richTextKey),
|
isSelected: editorState.isTextDecorationSelected(richTextKey) &&
|
||||||
|
editorState.toggledStyle[richTextKey] != true,
|
||||||
iconPadding: const EdgeInsets.symmetric(
|
iconPadding: const EdgeInsets.symmetric(
|
||||||
vertical: 14.0,
|
vertical: 14.0,
|
||||||
),
|
),
|
||||||
|
@ -68,7 +68,7 @@ class BlockItems extends StatelessWidget {
|
|||||||
enableTopRightRadius: false,
|
enableTopRightRadius: false,
|
||||||
enableBottomRightRadius: false,
|
enableBottomRightRadius: false,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await editorState.convertBlockType(blockType);
|
await _convert(blockType);
|
||||||
},
|
},
|
||||||
backgroundColor: theme.toolbarMenuItemBackgroundColor,
|
backgroundColor: theme.toolbarMenuItemBackgroundColor,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
@ -196,4 +196,23 @@ class BlockItems extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
editorState.service.keyboardService?.closeKeyboard();
|
editorState.service.keyboardService?.closeKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _convert(String blockType) async {
|
||||||
|
await editorState.convertBlockType(
|
||||||
|
blockType,
|
||||||
|
selectionExtraInfo: {
|
||||||
|
selectionExtraInfoDoNotAttachTextService: true,
|
||||||
|
selectionExtraInfoDisableFloatingToolbar: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
unawaited(
|
||||||
|
editorState.updateSelectionWithReason(
|
||||||
|
editorState.selection,
|
||||||
|
extraInfo: {
|
||||||
|
selectionExtraInfoDisableFloatingToolbar: true,
|
||||||
|
selectionExtraInfoDoNotAttachTextService: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ class _TextColorAndBackgroundColorState
|
|||||||
);
|
);
|
||||||
final String? selectedBackgroundColor =
|
final String? selectedBackgroundColor =
|
||||||
widget.editorState.getDeltaAttributeValueInSelection(
|
widget.editorState.getDeltaAttributeValueInSelection(
|
||||||
AppFlowyRichTextKeys.highlightColor,
|
AppFlowyRichTextKeys.backgroundColor,
|
||||||
widget.selection,
|
widget.selection,
|
||||||
);
|
);
|
||||||
return Column(
|
return Column(
|
||||||
@ -122,7 +122,7 @@ class _TextColorAndBackgroundColorState
|
|||||||
await widget.editorState.formatDelta(
|
await widget.editorState.formatDelta(
|
||||||
widget.selection,
|
widget.selection,
|
||||||
{
|
{
|
||||||
AppFlowyRichTextKeys.highlightColor: hex,
|
AppFlowyRichTextKeys.backgroundColor: hex,
|
||||||
},
|
},
|
||||||
selectionExtraInfo: {
|
selectionExtraInfo: {
|
||||||
selectionExtraInfoDisableFloatingToolbar: true,
|
selectionExtraInfoDisableFloatingToolbar: true,
|
||||||
|
@ -15,6 +15,7 @@ final aaToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
pilotAtExpandedSelection: true,
|
pilotAtExpandedSelection: true,
|
||||||
itemBuilder: (context, editorState, service, onMenu, _) {
|
itemBuilder: (context, editorState, service, onMenu, _) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
isSelected: () => service.showMenuNotifier.value,
|
isSelected: () => service.showMenuNotifier.value,
|
||||||
keepSelectedStatus: true,
|
keepSelectedStatus: true,
|
||||||
icon: FlowySvgs.m_toolbar_aa_s,
|
icon: FlowySvgs.m_toolbar_aa_s,
|
||||||
|
@ -18,6 +18,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
final addBlockToolbarItem = AppFlowyMobileToolbarItem(
|
final addBlockToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, service, __, onAction) {
|
itemBuilder: (context, editorState, service, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
icon: FlowySvgs.m_toolbar_add_s,
|
icon: FlowySvgs.m_toolbar_add_s,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final selection = editorState.selection;
|
final selection = editorState.selection;
|
||||||
@ -83,7 +84,7 @@ Future<bool?> showAddBlockMenu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AddBlockMenu extends StatelessWidget {
|
class _AddBlockMenu extends StatelessWidget {
|
||||||
_AddBlockMenu({
|
const _AddBlockMenu({
|
||||||
required this.selection,
|
required this.selection,
|
||||||
required this.editorState,
|
required this.editorState,
|
||||||
});
|
});
|
||||||
@ -91,151 +92,10 @@ class _AddBlockMenu extends StatelessWidget {
|
|||||||
final Selection selection;
|
final Selection selection;
|
||||||
final EditorState editorState;
|
final EditorState editorState;
|
||||||
|
|
||||||
late final List<TypeOptionMenuItemValue<String>> typeOptionMenuItemValue = [
|
|
||||||
// heading 1 - 3
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: HeadingBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFBAC9FF),
|
|
||||||
text: LocaleKeys.editor_heading1.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_h1_s,
|
|
||||||
onTap: (_, __) => _insertBlock(headingNode(level: 1)),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: HeadingBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFBAC9FF),
|
|
||||||
text: LocaleKeys.editor_heading2.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_h2_s,
|
|
||||||
onTap: (_, __) => _insertBlock(headingNode(level: 2)),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: HeadingBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFBAC9FF),
|
|
||||||
text: LocaleKeys.editor_heading3.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_h3_s,
|
|
||||||
onTap: (_, __) => _insertBlock(headingNode(level: 3)),
|
|
||||||
),
|
|
||||||
|
|
||||||
// paragraph
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: ParagraphBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFBAC9FF),
|
|
||||||
text: LocaleKeys.editor_text.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_paragraph_s,
|
|
||||||
onTap: (_, __) => _insertBlock(paragraphNode()),
|
|
||||||
),
|
|
||||||
|
|
||||||
// checkbox
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: TodoListBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFF98F4CD),
|
|
||||||
text: LocaleKeys.editor_checkbox.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_checkbox_s,
|
|
||||||
onTap: (_, __) => _insertBlock(todoListNode(checked: false)),
|
|
||||||
),
|
|
||||||
|
|
||||||
// quote
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: QuoteBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFFDEDA7),
|
|
||||||
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: const Color(0xFFFFB9EF),
|
|
||||||
text: LocaleKeys.editor_bulletedListShortForm.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_bulleted_list_s,
|
|
||||||
onTap: (_, __) => _insertBlock(bulletedListNode()),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: NumberedListBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFFFB9EF),
|
|
||||||
text: LocaleKeys.editor_numberedListShortForm.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_numbered_list_s,
|
|
||||||
onTap: (_, __) => _insertBlock(numberedListNode()),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: ToggleListBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFFFB9EF),
|
|
||||||
text: LocaleKeys.editor_toggleListShortForm.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_toggle_s,
|
|
||||||
onTap: (_, __) => _insertBlock(toggleListBlockNode()),
|
|
||||||
),
|
|
||||||
|
|
||||||
// image
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: DividerBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFF98F4CD),
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
// date
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: ParagraphBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFF91EAF5),
|
|
||||||
text: LocaleKeys.editor_date.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_date_s,
|
|
||||||
onTap: (_, __) => _insertBlock(dateMentionNode()),
|
|
||||||
),
|
|
||||||
|
|
||||||
// divider
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: DividerBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFF98F4CD),
|
|
||||||
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: const Color(0xFFCABDFF),
|
|
||||||
text: LocaleKeys.document_plugins_callout.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_callout_s,
|
|
||||||
onTap: (_, __) => _insertBlock(calloutNode()),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: CodeBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFCABDFF),
|
|
||||||
text: LocaleKeys.editor_codeBlockShortForm.tr(),
|
|
||||||
icon: FlowySvgs.m_add_block_code_s,
|
|
||||||
onTap: (_, __) => _insertBlock(codeBlockNode()),
|
|
||||||
),
|
|
||||||
TypeOptionMenuItemValue(
|
|
||||||
value: MathEquationBlockKeys.type,
|
|
||||||
backgroundColor: const Color(0xFFCABDFF),
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TypeOptionMenu<String>(
|
return TypeOptionMenu<String>(
|
||||||
values: typeOptionMenuItemValue,
|
values: buildTypeOptionMenuItemValues(context),
|
||||||
scaleFactor: context.scale,
|
scaleFactor: context.scale,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -249,6 +109,188 @@ class _AddBlockMenu extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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()),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// date
|
||||||
|
TypeOptionMenuItemValue(
|
||||||
|
value: ParagraphBlockKeys.type,
|
||||||
|
backgroundColor: colorMap['date']!,
|
||||||
|
text: LocaleKeys.editor_date.tr(),
|
||||||
|
icon: FlowySvgs.m_add_block_date_s,
|
||||||
|
onTap: (_, __) => _insertBlock(dateMentionNode()),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
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),
|
||||||
|
'date': 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),
|
||||||
|
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),
|
||||||
|
'date': const Color(0xFF91EAF5),
|
||||||
|
DividerBlockKeys.type: const Color(0xFF98F4CD),
|
||||||
|
CalloutBlockKeys.type: const Color(0xFFCABDFF),
|
||||||
|
CodeBlockKeys.type: const Color(0xFFCABDFF),
|
||||||
|
MathEquationBlockKeys.type: const Color(0xFFCABDFF),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension on EditorState {
|
extension on EditorState {
|
||||||
|
@ -270,6 +270,11 @@ class _MobileToolbarState extends State<_MobileToolbar>
|
|||||||
widget.editorState.selection = null;
|
widget.editorState.selection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the menu is shown and the height is not 0, we need to close the menu
|
||||||
|
if (showMenuNotifier.value && height != 0) {
|
||||||
|
closeItemMenu();
|
||||||
|
}
|
||||||
|
|
||||||
if (canUpdateCachedKeyboardHeight) {
|
if (canUpdateCachedKeyboardHeight) {
|
||||||
cachedKeyboardHeight.value = height;
|
cachedKeyboardHeight.value = height;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_toolbar_theme.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_toolbar_theme.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart';
|
||||||
@ -42,7 +44,9 @@ class AppFlowyMobileToolbarIconItem extends StatefulWidget {
|
|||||||
this.keepSelectedStatus = false,
|
this.keepSelectedStatus = false,
|
||||||
this.iconBuilder,
|
this.iconBuilder,
|
||||||
this.isSelected,
|
this.isSelected,
|
||||||
|
this.shouldListenToToggledStyle = false,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
|
required this.editorState,
|
||||||
});
|
});
|
||||||
|
|
||||||
final FlowySvgData? icon;
|
final FlowySvgData? icon;
|
||||||
@ -50,6 +54,8 @@ class AppFlowyMobileToolbarIconItem extends StatefulWidget {
|
|||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final WidgetBuilder? iconBuilder;
|
final WidgetBuilder? iconBuilder;
|
||||||
final bool Function()? isSelected;
|
final bool Function()? isSelected;
|
||||||
|
final bool shouldListenToToggledStyle;
|
||||||
|
final EditorState editorState;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AppFlowyMobileToolbarIconItem> createState() =>
|
State<AppFlowyMobileToolbarIconItem> createState() =>
|
||||||
@ -59,12 +65,28 @@ class AppFlowyMobileToolbarIconItem extends StatefulWidget {
|
|||||||
class _AppFlowyMobileToolbarIconItemState
|
class _AppFlowyMobileToolbarIconItemState
|
||||||
extends State<AppFlowyMobileToolbarIconItem> {
|
extends State<AppFlowyMobileToolbarIconItem> {
|
||||||
bool isSelected = false;
|
bool isSelected = false;
|
||||||
|
StreamSubscription? _subscription;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
isSelected = widget.isSelected?.call() ?? false;
|
isSelected = widget.isSelected?.call() ?? false;
|
||||||
|
if (widget.shouldListenToToggledStyle) {
|
||||||
|
widget.editorState.toggledStyleNotifier.addListener(_rebuild);
|
||||||
|
_subscription = widget.editorState.transactionStream.listen((_) {
|
||||||
|
_rebuild();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
if (widget.shouldListenToToggledStyle) {
|
||||||
|
widget.editorState.toggledStyleNotifier.removeListener(_rebuild);
|
||||||
|
_subscription?.cancel();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -85,15 +107,7 @@ class _AppFlowyMobileToolbarIconItemState
|
|||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.onTap();
|
widget.onTap();
|
||||||
if (widget.keepSelectedStatus && widget.isSelected == null) {
|
_rebuild();
|
||||||
setState(() {
|
|
||||||
isSelected = !isSelected;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
isSelected = widget.isSelected?.call() ?? false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 48,
|
width: 48,
|
||||||
@ -111,4 +125,12 @@ class _AppFlowyMobileToolbarIconItemState
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _rebuild() {
|
||||||
|
setState(() {
|
||||||
|
isSelected = (widget.keepSelectedStatus && widget.isSelected == null)
|
||||||
|
? !isSelected
|
||||||
|
: widget.isSelected?.call() ?? false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,13 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
|||||||
final boldToolbarItem = AppFlowyMobileToolbarItem(
|
final boldToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
isSelected: () => editorState.isTextDecorationSelected(
|
editorState: editorState,
|
||||||
AppFlowyRichTextKeys.bold,
|
shouldListenToToggledStyle: true,
|
||||||
),
|
isSelected: () =>
|
||||||
|
editorState.isTextDecorationSelected(
|
||||||
|
AppFlowyRichTextKeys.bold,
|
||||||
|
) &&
|
||||||
|
editorState.toggledStyle[AppFlowyRichTextKeys.bold] != false,
|
||||||
icon: FlowySvgs.m_toolbar_bold_s,
|
icon: FlowySvgs.m_toolbar_bold_s,
|
||||||
onTap: () async => editorState.toggleAttribute(
|
onTap: () async => editorState.toggleAttribute(
|
||||||
AppFlowyRichTextKeys.bold,
|
AppFlowyRichTextKeys.bold,
|
||||||
@ -23,7 +27,8 @@ final boldToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
final italicToolbarItem = AppFlowyMobileToolbarItem(
|
final italicToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
// keepSelectedStatus: true,
|
editorState: editorState,
|
||||||
|
shouldListenToToggledStyle: true,
|
||||||
isSelected: () => editorState.isTextDecorationSelected(
|
isSelected: () => editorState.isTextDecorationSelected(
|
||||||
AppFlowyRichTextKeys.italic,
|
AppFlowyRichTextKeys.italic,
|
||||||
),
|
),
|
||||||
@ -41,6 +46,8 @@ final italicToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
final underlineToolbarItem = AppFlowyMobileToolbarItem(
|
final underlineToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
|
shouldListenToToggledStyle: true,
|
||||||
isSelected: () => editorState.isTextDecorationSelected(
|
isSelected: () => editorState.isTextDecorationSelected(
|
||||||
AppFlowyRichTextKeys.underline,
|
AppFlowyRichTextKeys.underline,
|
||||||
),
|
),
|
||||||
@ -58,6 +65,8 @@ final underlineToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
final colorToolbarItem = AppFlowyMobileToolbarItem(
|
final colorToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, service, __, onAction) {
|
itemBuilder: (context, editorState, service, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
|
shouldListenToToggledStyle: true,
|
||||||
icon: FlowySvgs.m_toolbar_color_s,
|
icon: FlowySvgs.m_toolbar_color_s,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
service.closeKeyboard();
|
service.closeKeyboard();
|
||||||
|
@ -6,6 +6,8 @@ final todoListToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
final isSelected = editorState.isBlockTypeSelected(TodoListBlockKeys.type);
|
final isSelected = editorState.isBlockTypeSelected(TodoListBlockKeys.type);
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
|
shouldListenToToggledStyle: true,
|
||||||
keepSelectedStatus: true,
|
keepSelectedStatus: true,
|
||||||
isSelected: () => isSelected,
|
isSelected: () => isSelected,
|
||||||
icon: FlowySvgs.m_toolbar_checkbox_s,
|
icon: FlowySvgs.m_toolbar_checkbox_s,
|
||||||
|
@ -4,6 +4,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.da
|
|||||||
final moreToolbarItem = AppFlowyMobileToolbarItem(
|
final moreToolbarItem = AppFlowyMobileToolbarItem(
|
||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
icon: FlowySvgs.m_toolbar_more_s,
|
icon: FlowySvgs.m_toolbar_more_s,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,7 @@ final undoToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
final theme = ToolbarColorExtension.of(context);
|
final theme = ToolbarColorExtension.of(context);
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
iconBuilder: (context) {
|
iconBuilder: (context) {
|
||||||
final canUndo = editorState.undoManager.undoStack.isNonEmpty;
|
final canUndo = editorState.undoManager.undoStack.isNonEmpty;
|
||||||
return FlowySvg(
|
return FlowySvg(
|
||||||
@ -26,6 +27,7 @@ final redoToolbarItem = AppFlowyMobileToolbarItem(
|
|||||||
itemBuilder: (context, editorState, _, __, onAction) {
|
itemBuilder: (context, editorState, _, __, onAction) {
|
||||||
final theme = ToolbarColorExtension.of(context);
|
final theme = ToolbarColorExtension.of(context);
|
||||||
return AppFlowyMobileToolbarIconItem(
|
return AppFlowyMobileToolbarIconItem(
|
||||||
|
editorState: editorState,
|
||||||
iconBuilder: (context) {
|
iconBuilder: (context) {
|
||||||
final canRedo = editorState.undoManager.redoStack.isNonEmpty;
|
final canRedo = editorState.undoManager.redoStack.isNonEmpty;
|
||||||
return FlowySvg(
|
return FlowySvg(
|
||||||
|
@ -53,8 +53,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "9d90053"
|
ref: d4d35c0
|
||||||
resolved-ref: "9d9005366ba8383e93029c4f2f006f9ff8d1cb08"
|
resolved-ref: d4d35c0d103a5d1bddf68181fcfaf9f75b0fccb5
|
||||||
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
||||||
source: git
|
source: git
|
||||||
version: "2.3.2"
|
version: "2.3.2"
|
||||||
|
@ -167,7 +167,7 @@ dependency_overrides:
|
|||||||
appflowy_editor:
|
appflowy_editor:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||||
ref: "9d90053"
|
ref: "d4d35c0"
|
||||||
|
|
||||||
sheet:
|
sheet:
|
||||||
git:
|
git:
|
||||||
|
Loading…
Reference in New Issue
Block a user