feat: add image block on mobile (#4230)

This commit is contained in:
Lucas.Xu 2023-12-28 20:39:18 +08:00 committed by GitHub
parent 0b3c904984
commit 30a28b12d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 73 additions and 5 deletions

View File

@ -47,4 +47,9 @@
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<queries>
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
</manifest> </manifest>

View File

@ -67,6 +67,9 @@ class MobileBlockActionButtons extends StatelessWidget {
} }
void _showBottomSheet(BuildContext context) { void _showBottomSheet(BuildContext context) {
// close the keyboard
editorState.updateSelectionWithReason(null, extraInfo: {});
showMobileBottomSheet( showMobileBottomSheet(
context, context,
showHeader: true, showHeader: true,

View File

@ -104,6 +104,7 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
} else { } else {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
editorState.updateSelectionWithReason(null, extraInfo: {});
showUploadImageMenu(); showUploadImageMenu();
}, },
child: child, child: child,

View File

@ -59,6 +59,7 @@ extension InsertImage on EditorState {
offset: 0, offset: 0,
), ),
); );
transaction.selectionExtraInfo = {};
return apply(transaction); return apply(transaction);
} }

View File

@ -1,16 +1,18 @@
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/util.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class IndentAndOutdentItems extends StatelessWidget { class IndentAndOutdentItems extends StatelessWidget {
const IndentAndOutdentItems({ const IndentAndOutdentItems({
super.key, super.key,
required this.service,
required this.editorState, required this.editorState,
}); });
final EditorState editorState; final EditorState editorState;
final AppFlowyMobileToolbarWidgetService service;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -28,6 +30,7 @@ class IndentAndOutdentItems extends StatelessWidget {
iconPadding: const EdgeInsets.symmetric(vertical: 14.0), iconPadding: const EdgeInsets.symmetric(vertical: 14.0),
backgroundColor: theme.toolbarMenuItemBackgroundColor, backgroundColor: theme.toolbarMenuItemBackgroundColor,
onTap: () { onTap: () {
service.closeItemMenu();
outdentCommand.execute(editorState); outdentCommand.execute(editorState);
}, },
), ),
@ -42,6 +45,7 @@ class IndentAndOutdentItems extends StatelessWidget {
iconPadding: const EdgeInsets.symmetric(vertical: 14.0), iconPadding: const EdgeInsets.symmetric(vertical: 14.0),
backgroundColor: theme.toolbarMenuItemBackgroundColor, backgroundColor: theme.toolbarMenuItemBackgroundColor,
onTap: () { onTap: () {
service.closeItemMenu();
indentCommand.execute(editorState); indentCommand.execute(editorState);
}, },
), ),

View File

@ -106,6 +106,7 @@ class _TextDecorationMenuState extends State<_TextDecorationMenu> {
), ),
const Spacer(), const Spacer(),
IndentAndOutdentItems( IndentAndOutdentItems(
service: widget.service,
editorState: editorState, editorState: editorState,
), ),
], ],

View File

@ -1,6 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.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_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/mobile_toolbar_v3/_toolbar_theme.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
@ -184,7 +185,7 @@ class _AddBlockMenu extends StatelessWidget {
onTap: () => _insertBlock(quoteNode()), onTap: () => _insertBlock(quoteNode()),
), ),
// divider, // divider
_AddBlockMenuItemData( _AddBlockMenuItemData(
blockType: DividerBlockKeys.type, blockType: DividerBlockKeys.type,
backgroundColor: const Color(0xFF98F4CD), 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<ImagePlaceholderState>();
await editorState.insertEmptyImageBlock(imagePlaceholderKey);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
imagePlaceholderKey.currentState?.controller.show();
});
});
},
),
]; ];
@override @override
@ -257,7 +277,7 @@ class _AddBlockMenuItem extends StatelessWidget {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
), ),
padding: const EdgeInsets.all(24), padding: EdgeInsets.all(20 * context.scale),
child: FlowySvg( child: FlowySvg(
data.icon, data.icon,
color: Colors.black, color: Colors.black,
@ -266,7 +286,7 @@ class _AddBlockMenuItem extends StatelessWidget {
const VSpace(4), const VSpace(4),
FlowyText( FlowyText(
data.text, data.text,
fontSize: 13.0, fontSize: 12.0,
), ),
], ],
), ),

View File

@ -540,7 +540,8 @@ class _ToolbarItemListViewState extends State<_ToolbarItemListView> {
} }
final toolbarItems = widget.toolbarItems; 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( final index = toolbarItems.indexWhere(
(element) => selection.isCollapsed (element) => selection.isCollapsed
? element.pilotAtCollapsedSelection ? element.pilotAtCollapsedSelection

View File

@ -1,3 +1,4 @@
import 'package:appflowy/startup/tasks/prelude.dart';
import 'package:keyboard_height_plugin/keyboard_height_plugin.dart'; import 'package:keyboard_height_plugin/keyboard_height_plugin.dart';
typedef KeyboardHeightCallback = void Function(double height); typedef KeyboardHeightCallback = void Function(double height);
@ -32,6 +33,12 @@ class KeyboardHeightObserver {
} }
void notify(double height) { 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) { for (final listener in _listeners) {
listener(height); listener(height);
} }

View File

@ -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. // there's a flag named _enable in memory_leak_detector.dart. If it's false, the task will be ignored.
MemoryLeakDetectorTask(), MemoryLeakDetectorTask(),
const DebugTask(), const DebugTask(),
const DeviceInfoTask(),
// localization // localization
const InitLocalizationTask(), const InitLocalizationTask(),
// init the app window // init the app window

View File

@ -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<void> initialize(LaunchContext context) async {
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo;
androidSDKVersion = androidInfo.version.sdkInt;
}
}
@override
Future<void> dispose() async {}
}

View File

@ -1,6 +1,7 @@
export 'app_widget.dart'; export 'app_widget.dart';
export 'appflowy_cloud_task.dart'; export 'appflowy_cloud_task.dart';
export 'debug_task.dart'; export 'debug_task.dart';
export 'device_info_task.dart';
export 'generate_router.dart'; export 'generate_router.dart';
export 'hot_key.dart'; export 'hot_key.dart';
export 'load_plugin.dart'; export 'load_plugin.dart';