diff --git a/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml b/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml index 74a83ed9f2..4c4436244c 100644 --- a/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml +++ b/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml @@ -47,4 +47,9 @@ + + + + + \ No newline at end of file diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart index 705356481e..c8c0501690 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart @@ -67,6 +67,9 @@ class MobileBlockActionButtons extends StatelessWidget { } void _showBottomSheet(BuildContext context) { + // close the keyboard + editorState.updateSelectionWithReason(null, extraInfo: {}); + showMobileBottomSheet( context, showHeader: true, diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_placeholder.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_placeholder.dart index df21655f42..d8a9f43151 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_placeholder.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_placeholder.dart @@ -104,6 +104,7 @@ class ImagePlaceholderState extends State { } else { return GestureDetector( onTap: () { + editorState.updateSelectionWithReason(null, extraInfo: {}); showUploadImageMenu(); }, child: child, diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_selection_menu.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_selection_menu.dart index 9a1d98a11e..261f00af89 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_selection_menu.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/image_selection_menu.dart @@ -59,6 +59,7 @@ extension InsertImage on EditorState { offset: 0, ), ); + transaction.selectionExtraInfo = {}; return apply(transaction); } diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_indent_items.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_indent_items.dart index 09ab3343ee..0188ceef2e 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_indent_items.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_indent_items.dart @@ -1,16 +1,18 @@ 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/util.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/material.dart'; class IndentAndOutdentItems extends StatelessWidget { const IndentAndOutdentItems({ super.key, + required this.service, required this.editorState, }); final EditorState editorState; + final AppFlowyMobileToolbarWidgetService service; @override Widget build(BuildContext context) { @@ -28,6 +30,7 @@ class IndentAndOutdentItems extends StatelessWidget { iconPadding: const EdgeInsets.symmetric(vertical: 14.0), backgroundColor: theme.toolbarMenuItemBackgroundColor, onTap: () { + service.closeItemMenu(); outdentCommand.execute(editorState); }, ), @@ -42,6 +45,7 @@ class IndentAndOutdentItems extends StatelessWidget { iconPadding: const EdgeInsets.symmetric(vertical: 14.0), backgroundColor: theme.toolbarMenuItemBackgroundColor, onTap: () { + service.closeItemMenu(); indentCommand.execute(editorState); }, ), diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_toolbar_item.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_toolbar_item.dart index 23f5d7b273..999e6607b9 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_toolbar_item.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_toolbar_item.dart @@ -106,6 +106,7 @@ class _TextDecorationMenuState extends State<_TextDecorationMenu> { ), const Spacer(), IndentAndOutdentItems( + service: widget.service, editorState: editorState, ), ], diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart index 3526bde45c..60a65ec043 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart @@ -1,6 +1,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.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/mobile_toolbar_item/mobile_add_block_toolbar_item.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_toolbar_theme.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; @@ -184,7 +185,7 @@ class _AddBlockMenu extends StatelessWidget { onTap: () => _insertBlock(quoteNode()), ), - // divider, + // divider _AddBlockMenuItemData( blockType: DividerBlockKeys.type, backgroundColor: const Color(0xFF98F4CD), @@ -197,6 +198,25 @@ class _AddBlockMenu extends StatelessWidget { }); }, ), + + // image + _AddBlockMenuItemData( + blockType: DividerBlockKeys.type, + backgroundColor: const Color(0xFF98F4CD), + text: LocaleKeys.editor_image.tr(), + icon: FlowySvgs.m_toolbar_imae_lg, + onTap: () async { + AppGlobals.rootNavKey.currentContext?.pop(true); + Future.delayed(const Duration(milliseconds: 400), () async { + final imagePlaceholderKey = GlobalKey(); + await editorState.insertEmptyImageBlock(imagePlaceholderKey); + + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + imagePlaceholderKey.currentState?.controller.show(); + }); + }); + }, + ), ]; @override @@ -257,7 +277,7 @@ class _AddBlockMenuItem extends StatelessWidget { borderRadius: BorderRadius.circular(20), ), ), - padding: const EdgeInsets.all(24), + padding: EdgeInsets.all(20 * context.scale), child: FlowySvg( data.icon, color: Colors.black, @@ -266,7 +286,7 @@ class _AddBlockMenuItem extends StatelessWidget { const VSpace(4), FlowyText( data.text, - fontSize: 13.0, + fontSize: 12.0, ), ], ), diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart index 82e42cceb5..b65008a231 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar.dart @@ -540,7 +540,8 @@ class _ToolbarItemListViewState extends State<_ToolbarItemListView> { } final toolbarItems = widget.toolbarItems; - final alignment = selection.isCollapsed ? 0.0 : -1.0; + // use -0.4 to make sure the pilot is in the front of the toolbar item + final alignment = selection.isCollapsed ? 0.0 : -0.4; final index = toolbarItems.indexWhere( (element) => selection.isCollapsed ? element.pilotAtCollapsedSelection diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/keyboard_height_observer.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/keyboard_height_observer.dart index a58a214db4..b4d36cbd23 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/keyboard_height_observer.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/keyboard_height_observer.dart @@ -1,3 +1,4 @@ +import 'package:appflowy/startup/tasks/prelude.dart'; import 'package:keyboard_height_plugin/keyboard_height_plugin.dart'; typedef KeyboardHeightCallback = void Function(double height); @@ -32,6 +33,12 @@ class KeyboardHeightObserver { } void notify(double height) { + // the keyboard height will notify twice with the same value on Android 14 + if (DeviceInfoTask.androidSDKVersion == 34) { + if (height == 0 && currentKeyboardHeight == 0) { + return; + } + } for (final listener in _listeners) { listener(height); } diff --git a/frontend/appflowy_flutter/lib/startup/startup.dart b/frontend/appflowy_flutter/lib/startup/startup.dart index 2005c9e76e..b27b88e0ec 100644 --- a/frontend/appflowy_flutter/lib/startup/startup.dart +++ b/frontend/appflowy_flutter/lib/startup/startup.dart @@ -103,6 +103,7 @@ class FlowyRunner { // there's a flag named _enable in memory_leak_detector.dart. If it's false, the task will be ignored. MemoryLeakDetectorTask(), const DebugTask(), + const DeviceInfoTask(), // localization const InitLocalizationTask(), // init the app window diff --git a/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart b/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart new file mode 100644 index 0000000000..6dd5af5032 --- /dev/null +++ b/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart @@ -0,0 +1,23 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; + +import '../startup.dart'; + +class DeviceInfoTask extends LaunchTask { + const DeviceInfoTask(); + + static int androidSDKVersion = -1; + + @override + Future initialize(LaunchContext context) async { + final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + if (Platform.isAndroid) { + final androidInfo = await deviceInfoPlugin.androidInfo; + androidSDKVersion = androidInfo.version.sdkInt; + } + } + + @override + Future dispose() async {} +} diff --git a/frontend/appflowy_flutter/lib/startup/tasks/prelude.dart b/frontend/appflowy_flutter/lib/startup/tasks/prelude.dart index 6d21cdb178..c19f9e8d65 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/prelude.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/prelude.dart @@ -1,6 +1,7 @@ export 'app_widget.dart'; export 'appflowy_cloud_task.dart'; export 'debug_task.dart'; +export 'device_info_task.dart'; export 'generate_router.dart'; export 'hot_key.dart'; export 'load_plugin.dart';