feat: add more showcases on the mobile platform (#479)

This commit is contained in:
Lucas.Xu 2023-09-18 22:05:17 +08:00 • committed by GitHub
commit 6699d58631
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 245 additions and 214 deletions

View file

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.8.0'
repositories {
google()
mavenCentral()

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

View file

@ -68,7 +68,6 @@
EA2F6824C2F8DF616F38D702 /* Pods-Runner.release.xcconfig */,
8ED982CC43DE110A1567B441 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@ -359,14 +358,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 446D3AAR7E;
DEVELOPMENT_TEAM = KD48NC6JW7;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.editor;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -488,14 +487,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 446D3AAR7E;
DEVELOPMENT_TEAM = KD48NC6JW7;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.editor;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -511,14 +510,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 446D3AAR7E;
DEVELOPMENT_TEAM = KD48NC6JW7;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.editor;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

View file

@ -1,55 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true />
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false />
<key>CADisableMinimumFrameDurationOnPhone</key>
<true />
<key>UIApplicationSupportsIndirectInputEvents</key>
<true />
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
</array>
</dict>
</plist>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -83,7 +83,8 @@ class _HomePageState extends State<HomePage> {
extendBodyBehindAppBar: PlatformExtension.isDesktopOrWeb,
drawer: _buildDrawer(context),
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
backgroundColor: const Color.fromARGB(255, 134, 46, 247),
foregroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
title: const Text('AppFlowy Editor'),
),
@ -100,7 +101,7 @@ class _HomePageState extends State<HomePage> {
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
child: Image.asset(
'assets/images/icon.png',
'assets/images/icon.jpeg',
fit: BoxFit.fill,
),
),

View file

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:example/pages/mobile_editor.dart';
import 'package:flutter/material.dart';
class Editor extends StatelessWidget {
@ -65,30 +66,9 @@ class Editor extends StatelessWidget {
),
);
} else if (PlatformExtension.isMobile) {
return Column(
children: [
Expanded(
child: _buildMobileEditor(
context,
editorState,
editorScrollController,
),
),
MobileToolbar(
editorState: editorState,
toolbarItems: [
textDecorationMobileToolbarItem,
buildTextAndBackgroundColorMobileToolbarItem(),
headingMobileToolbarItem,
todoListMobileToolbarItem,
listMobileToolbarItem,
linkMobileToolbarItem,
quoteMobileToolbarItem,
dividerMobileToolbarItem,
codeMobileToolbarItem,
],
),
],
return MobileEditor(
editorState: editorState,
onEditorStateChange: onEditorStateChange,
);
}
}
@ -99,18 +79,6 @@ class Editor extends StatelessWidget {
);
}
Widget _buildMobileEditor(
BuildContext context,
EditorState editorState,
EditorScrollController? editorScrollController,
) {
return AppFlowyEditor(
editorStyle: const EditorStyle.mobile(),
editorState: editorState,
editorScrollController: editorScrollController,
);
}
Widget _buildDesktopEditor(
BuildContext context,
EditorState editorState,

View file

@ -0,0 +1,141 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class MobileEditor extends StatefulWidget {
const MobileEditor({
super.key,
required this.editorState,
required this.onEditorStateChange,
this.editorStyle,
});
final EditorState editorState;
final EditorStyle? editorStyle;
final void Function(EditorState editorState) onEditorStateChange;
@override
State<MobileEditor> createState() => _MobileEditorState();
}
class _MobileEditorState extends State<MobileEditor> {
EditorState get editorState => widget.editorState;
late final EditorScrollController editorScrollController;
late EditorStyle editorStyle;
late Map<String, BlockComponentBuilder> blockComponentBuilders;
@override
void initState() {
super.initState();
// customize the log configuration
editorState.logConfiguration
..handler = debugPrint
..level = LogLevel.off;
// listen to editor state change
editorState.transactionStream.listen((event) {
if (event.$1 == TransactionTime.after) {
widget.onEditorStateChange(editorState);
}
});
editorScrollController = EditorScrollController(
editorState: editorState,
shrinkWrap: false,
);
editorStyle = _buildMobileEditorStyle();
blockComponentBuilders = _buildBlockComponentBuilders();
}
@override
void reassemble() {
super.reassemble();
editorStyle = _buildMobileEditorStyle();
blockComponentBuilders = _buildBlockComponentBuilders();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
// build appflowy editor
Expanded(
child: AppFlowyEditor(
editorStyle: editorStyle,
editorState: editorState,
editorScrollController: editorScrollController,
blockComponentBuilders: blockComponentBuilders,
// showcase 3: customize the header and footer.
header: Image.asset(
'assets/images/icon.jpeg',
fit: BoxFit.fitWidth,
height: 100,
),
footer: const SizedBox(
height: 100,
),
),
),
// build mobile toolbar
MobileToolbar(
editorState: editorState,
toolbarItems: [
textDecorationMobileToolbarItem,
buildTextAndBackgroundColorMobileToolbarItem(),
headingMobileToolbarItem,
todoListMobileToolbarItem,
listMobileToolbarItem,
linkMobileToolbarItem,
quoteMobileToolbarItem,
dividerMobileToolbarItem,
codeMobileToolbarItem,
],
),
],
);
}
// showcase 1: customize the editor style.
EditorStyle _buildMobileEditorStyle() {
return EditorStyle.mobile(
cursorColor: Colors.blue,
selectionColor: Colors.blue.shade200,
textStyleConfiguration: TextStyleConfiguration(
text: GoogleFonts.poppins(
fontSize: 14,
color: Colors.black,
),
code: GoogleFonts.badScript(),
),
padding: const EdgeInsets.symmetric(horizontal: 14.0),
);
}
// showcase 2: customize the block style
Map<String, BlockComponentBuilder> _buildBlockComponentBuilders() {
final map = {
...standardBlockComponentBuilderMap,
};
// customize the heading block component
final levelToFontSize = [
24.0,
22.0,
20.0,
18.0,
16.0,
14.0,
];
map[HeadingBlockKeys.type] = HeadingBlockComponentBuilder(
textStyleBuilder: (level) => GoogleFonts.poppins(
fontSize: levelToFontSize.elementAtOrNull(level - 1) ?? 14.0,
fontWeight: FontWeight.w600,
),
);
return map;
}
}

View file

@ -69,7 +69,7 @@ flutter:
assets:
- assets/example.json
- assets/example.html
- assets/images/icon.png
- assets/images/icon.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware

View file

@ -144,11 +144,14 @@ class _HeadingBlockComponentWidgetState
node: widget.node,
editorState: editorState,
textAlign: alignment?.toTextAlign,
textSpanDecorator: (textSpan) =>
textSpan.updateTextStyle(textStyle).updateTextStyle(
widget.textStyleBuilder?.call(level) ??
defaultTextStyle(level),
),
textSpanDecorator: (textSpan) {
var result = textSpan.updateTextStyle(textStyle);
result = result.updateTextStyle(
widget.textStyleBuilder?.call(level) ??
defaultTextStyle(level),
);
return result;
},
placeholderText: placeholderText,
placeholderTextSpanDecorator: (textSpan) => textSpan
.updateTextStyle(

View file

@ -7,8 +7,9 @@ final Map<String, BlockComponentBuilder> standardBlockComponentBuilderMap = {
PageBlockKeys.type: PageBlockComponentBuilder(),
ParagraphBlockKeys.type: TextBlockComponentBuilder(
configuration: standardBlockComponentConfiguration.copyWith(
placeholderText: (_) =>
AppFlowyEditorLocalizations.current.slashPlaceHolder,
placeholderText: (_) => PlatformExtension.isDesktopOrWeb
? AppFlowyEditorLocalizations.current.slashPlaceHolder
: ' ',
),
),
TodoListBlockKeys.type: TodoListBlockComponentBuilder(

View file

@ -54,17 +54,19 @@ class PageBlockComponent extends BlockComponentStatelessWidget {
return Builder(
builder: (context) {
editorState.updateAutoScroller(Scrollable.of(context));
return Padding(
padding: editorState.editorStyle.padding,
child: Column(
children: [
if (header != null) header!,
...items
.map((e) => editorState.renderer.build(context, e))
.toList(),
if (footer != null) footer!,
],
),
return Column(
children: [
if (header != null) header!,
...items
.map(
(e) => Padding(
padding: editorState.editorStyle.padding,
child: editorState.renderer.build(context, e),
),
)
.toList(),
if (footer != null) footer!,
],
);
},
);
@ -75,16 +77,19 @@ class PageBlockComponent extends BlockComponentStatelessWidget {
return ScrollablePositionedList.builder(
shrinkWrap: scrollController.shrinkWrap,
padding: editorState.editorStyle.padding,
// padding: editorState.editorStyle.padding,
scrollDirection: Axis.vertical,
itemCount: items.length + extentCount,
itemBuilder: (context, index) {
editorState.updateAutoScroller(Scrollable.of(context));
if (header != null && index == 0) return header!;
if (footer != null && index == items.length + 1) return footer!;
return editorState.renderer.build(
context,
items[index - (header != null ? 1 : 0)],
return Padding(
padding: editorState.editorStyle.padding,
child: editorState.renderer.build(
context,
items[index - (header != null ? 1 : 0)],
),
);
},
itemScrollController: scrollController.itemScrollController,

View file

@ -416,6 +416,7 @@ class _MobileSelectionServiceWidgetState
rect: rect,
showLeftHandler: showLeftHandler,
showRightHandler: showRightHandler,
handlerColor: editorState.editorStyle.cursorColor,
),
);
_selectionAreas.add(overlay);

View file

@ -24,11 +24,6 @@ final CommandShortcutEvent moveCursorDownCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _moveCursorDownCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow down key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
final selection = editorState.selection;
if (selection == null) {
return KeyEventResult.ignored;

View file

@ -26,10 +26,6 @@ final CommandShortcutEvent moveCursorLeftCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _arrowLeftCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow left key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
if (isRTL(editorState)) {
editorState.moveCursorBackward(SelectionMoveRange.character);
} else {
@ -48,10 +44,6 @@ final CommandShortcutEvent moveCursorToBeginCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _moveCursorToBeginCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow left key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
if (isRTL(editorState)) {
editorState.moveCursorBackward(SelectionMoveRange.line);
} else {

View file

@ -26,10 +26,6 @@ final CommandShortcutEvent moveCursorRightCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _arrowRightCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow right key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
if (isRTL(editorState)) {
editorState.moveCursorForward(SelectionMoveRange.character);
} else {
@ -48,10 +44,6 @@ final CommandShortcutEvent moveCursorToEndCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _moveCursorToEndCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow right key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
if (isRTL(editorState)) {
editorState.moveCursorForward(SelectionMoveRange.line);
} else {

View file

@ -24,11 +24,6 @@ final CommandShortcutEvent moveCursorUpCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _moveCursorUpCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'arrow up key is not supported on mobile platform.');
return KeyEventResult.ignored;
}
final selection = editorState.selection;
if (selection == null) {
return KeyEventResult.ignored;

View file

@ -15,12 +15,7 @@ final CommandShortcutEvent copyCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _copyCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'copyCommand is not supported on mobile platform.');
return KeyEventResult.ignored;
}
var selection = editorState.selection?.normalized;
final selection = editorState.selection?.normalized;
if (selection == null || selection.isCollapsed) {
return KeyEventResult.ignored;
}

View file

@ -15,11 +15,6 @@ final CommandShortcutEvent cutCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _cutCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'cutCommand is not supported on mobile platform.');
return KeyEventResult.ignored;
}
// plain text.
handleCut(editorState);
return KeyEventResult.handled;

View file

@ -15,10 +15,6 @@ final CommandShortcutEvent endCommand = CommandShortcutEvent(
);
CommandShortcutEventHandler _endCommandHandler = (editorState) {
if (PlatformExtension.isMobile) {
assert(false, 'endCommand is not supported on mobile platform.');
return KeyEventResult.ignored;
}
final scrollService = editorState.service.scrollService;
if (scrollService == null) {
return KeyEventResult.ignored;

Some files were not shown because too many files have changed in this diff Show more