mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add image block on mobile (#4230)
This commit is contained in:
parent
0b3c904984
commit
30a28b12d1
@ -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>
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -59,6 +59,7 @@ extension InsertImage on EditorState {
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
transaction.selectionExtraInfo = {};
|
||||||
|
|
||||||
return apply(transaction);
|
return apply(transaction);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -106,6 +106,7 @@ class _TextDecorationMenuState extends State<_TextDecorationMenu> {
|
|||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IndentAndOutdentItems(
|
IndentAndOutdentItems(
|
||||||
|
service: widget.service,
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 {}
|
||||||
|
}
|
@ -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';
|
||||||
|
Loading…
Reference in New Issue
Block a user