Skip to content

Commit

Permalink
Merge branch 'main' into feat-zhiya
Browse files Browse the repository at this point in the history
* main:
  chore: bump version 2.3.4 (AppFlowy-IO#770)
  fix: count any non-whitespace character (AppFlowy-IO#771)
  feat: support customizing mobile page style (AppFlowy-IO#769)
  feat: add table style (AppFlowy-IO#766)
  feat: support auto complete for text block (AppFlowy-IO#764)
  • Loading branch information
q200892907 committed Apr 18, 2024
2 parents 1169632 + 680ada4 commit 9b31bdb
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 60 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
desktop:
strategy:
matrix:
os: [macos-13, macos-12, macos-11, ubuntu-22.04, ubuntu-20.04, windows-2022, windows-2019]
os: [macos-14, macos-13, macos-12, macos-11, ubuntu-22.04, ubuntu-20.04, windows-2022, windows-2019]

runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -52,6 +52,6 @@ jobs:
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
token: 398c9ded-28ad-4750-bfdb-e7f502539137
attempt_limit: 10
attempt_delay: 10000
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## 2.3.4
* feat: support customizing mobile page style by @LucasXu0 in [769](https://github.com/AppFlowy-IO/appflowy-editor/pull/769)
* feat: add table style by @q200892907 in [766](https://github.com/AppFlowy-IO/appflowy-editor/pull/766)
* feat: support auto complete for text block by @LucasXu0 in [764](https://github.com/AppFlowy-IO/appflowy-editor/pull/764)
* fix: unable to select multiple words by @LucasXu0 in [761](https://github.com/AppFlowy-IO/appflowy-editor/pull/761)
* fix: filter invalid text editing value by @LucasXu0 in [760](https://github.com/AppFlowy-IO/appflowy-editor/pull/760)
* feat: combine diff operations by @LucasXu0 in [759](https://github.com/AppFlowy-IO/appflowy-editor/pull/759)
* fix: delta insert error by @LucasXu0 in [758](https://github.com/AppFlowy-IO/appflowy-editor/pull/758)
* feat: add more gesture interceptors by @Xazin in [757](https://github.com/AppFlowy-IO/appflowy-editor/pull/757)
* feat: support remote selections by @LucasXu0 in [753](https://github.com/AppFlowy-IO/appflowy-editor/pull/753)
* fix: late initialization error by @LucasXu0 in [750](https://github.com/AppFlowy-IO/appflowy-editor/pull/750)
* feat: add diff document/nodes function by @LucasXu0 in [748](https://github.com/AppFlowy-IO/appflowy-editor/pull/748)
* fix: render paragraph hot reload error by @LucasXu0 in [742](https://github.com/AppFlowy-IO/appflowy-editor/pull/742)
* feat: disable converting heading block to numbered list block by @LucasXu0 in [740](https://github.com/AppFlowy-IO/appflowy-editor/pull/740)
* fix: xtra space from numbered list item by @lming in [724](https://github.com/AppFlowy-IO/appflowy-editor/pull/724)
* fix: disable tableActionHandler when the editorState is not editable by @Taverz in [733](https://github.com/AppFlowy-IO/appflowy-editor/pull/733)
* feat: add fixed toolbar example by @LucasXu0 in [739](https://github.com/AppFlowy-IO/appflowy-editor/pull/739)

## 2.3.3
* feat: word counter service by @Xazin in [706](https://github.com/AppFlowy-IO/appflowy-editor/pull/706)
* feat: support scaling the svg by @LucasXu0 in [722](https://github.com/AppFlowy-IO/appflowy-editor/pull/722)
Expand Down
9 changes: 9 additions & 0 deletions example/lib/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:math';

import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:example/pages/auto_complete_editor.dart';
import 'package:example/pages/collab_editor.dart';
import 'package:example/pages/collab_selection_editor.dart';
import 'package:example/pages/customize_theme_for_editor.dart';
Expand Down Expand Up @@ -161,6 +162,14 @@ class _HomePageState extends State<HomePage> {

// Theme Demo
_buildSeparator(context, 'Showcases'),
_buildListTile(context, 'Auto complete Editor', () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AutoCompleteEditor(),
),
);
}),
_buildListTile(context, 'Collab Editor', () {
Navigator.push(
context,
Expand Down
70 changes: 70 additions & 0 deletions example/lib/pages/auto_complete_editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

final _options = {
'hello ': 'world',
'support@g': 'mail.com',
'appflowy ': 'editor',
};

class AutoCompleteEditor extends StatelessWidget {
const AutoCompleteEditor({
super.key,
});

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
const SizedBox(height: 100),
Container(
height: 500,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
),
child: AppFlowyEditor(
editorState: EditorState(
document: Document.blank(withInitialText: true),
),
commandShortcutEvents: [
tabToAutoCompleteCommand,
...standardCommandShortcutEvents,
],
enableAutoComplete: true,
autoCompleteTextProvider: (context, node, textSpan) {
final editorState = context.read<EditorState>();
final selection = editorState.selection;
final delta = node.delta;
if (selection == null ||
delta == null ||
!selection.isCollapsed ||
selection.endIndex != delta.length ||
!node.path.equals(selection.start.path)) {
return null;
}
final text = delta.toPlainText().toLowerCase();
for (final option in _options.keys) {
if (text.endsWith(option)) {
return _options[option];
}
}
return null;
},
),
),
const SizedBox(height: 16),
Text(
'AutoComplete Options: $_options',
style: Theme.of(context).textTheme.titleLarge,
),
],
),
),
),
);
}
}
2 changes: 1 addition & 1 deletion example/lib/pages/customize_theme_for_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {
// todo-list block
TodoListBlockKeys.type: TodoListBlockComponentBuilder(
configuration: configuration,
iconBuilder: (context, node) {
iconBuilder: (context, node, ___) {
final checked = node.attributes[TodoListBlockKeys.checked] as bool;
return GestureDetector(
onTap: () => editorState.apply(
Expand Down
26 changes: 26 additions & 0 deletions example/lib/pages/desktop_editor.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

class DesktopEditor extends StatefulWidget {
const DesktopEditor({
Expand Down Expand Up @@ -84,6 +85,8 @@ class _DesktopEditorState extends State<DesktopEditor> {
blockComponentBuilders: blockComponentBuilders,
commandShortcutEvents: commandShortcuts,
editorStyle: editorStyle,
enableAutoComplete: true,
autoCompleteTextProvider: _buildAutoCompleteTextProvider,
header: Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Image.asset(
Expand Down Expand Up @@ -188,4 +191,27 @@ class _DesktopEditorState extends State<DesktopEditor> {
),
];
}

String? _buildAutoCompleteTextProvider(
BuildContext context,
Node node,
TextSpan? textSpan,
) {
final editorState = context.read<EditorState>();
final selection = editorState.selection;
final delta = node.delta;
if (selection == null ||
delta == null ||
!selection.isCollapsed ||
selection.endIndex != delta.length ||
!node.path.equals(selection.start.path)) {
return null;
}
final text = delta.toPlainText();
// An example, if the text ends with 'hello', then show the autocomplete.
if (text.endsWith('hello')) {
return ' world';
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';

// Add your custom block keys if it supports auto complete
final autoCompletableBlockTypes = {
ParagraphBlockKeys.type,
NumberedListBlockKeys.type,
TodoListBlockKeys.type,
BulletedListBlockKeys.type,
QuoteBlockKeys.type,
HeadingBlockKeys.type,
};

/// Auto complete the current block
///
/// - support
/// - desktop
/// - web
///
final CommandShortcutEvent tabToAutoCompleteCommand = CommandShortcutEvent(
key: 'tab to auto complete',
getDescription: () => 'Tab to auto complete',
command: 'tab',
handler: _tabToAutoCompleteCommandHandler,
);

CommandShortcutEventHandler _tabToAutoCompleteCommandHandler = (editorState) {
final selection = editorState.selection;
if (selection == null || !selection.isCollapsed) {
return KeyEventResult.ignored;
}

final context = editorState.document.root.context;
final node = editorState.getNodeAtPath(selection.end.path);
final delta = node?.delta;

// Now, this command only support auto complete the text if the cursor is at the end of the block
if (context == null ||
node == null ||
!autoCompletableBlockTypes.contains(node.type) ||
delta == null ||
selection.endIndex != delta.length) {
return KeyEventResult.ignored;
}

// Support async auto complete text provider in the future
final autoCompleteText = editorState.autoCompleteTextProvider?.call(
context,
node,
null,
);
if (autoCompleteText == null || autoCompleteText.isEmpty) {
return KeyEventResult.ignored;
}

final transaction = editorState.transaction
..insertText(
node,
selection.endIndex,
autoCompleteText,
);
editorState.apply(transaction);

return KeyEventResult.handled;
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class TextStyleConfiguration {
color: Colors.red,
backgroundColor: Color.fromARGB(98, 0, 195, 255),
),
this.autoComplete = const TextStyle(
color: Colors.grey,
),
this.applyHeightToFirstAscent = false,
this.applyHeightToLastDescent = false,
});

/// default text style
Expand All @@ -43,6 +48,13 @@ class TextStyleConfiguration {
/// code text style
final TextStyle code;

/// auto complete text style
final TextStyle autoComplete;

/// apply line height to the first or the last ascent
final bool applyHeightToFirstAscent;
final bool applyHeightToLastDescent;

TextStyleConfiguration copyWith({
TextStyle? text,
TextStyle? bold,
Expand All @@ -51,6 +63,9 @@ class TextStyleConfiguration {
TextStyle? strikethrough,
TextStyle? href,
TextStyle? code,
TextStyle? autoComplete,
bool? applyHeightToFirstAscent,
bool? applyHeightToLastDescent,
}) {
return TextStyleConfiguration(
text: text ?? this.text,
Expand All @@ -60,6 +75,11 @@ class TextStyleConfiguration {
strikethrough: strikethrough ?? this.strikethrough,
href: href ?? this.href,
code: code ?? this.code,
autoComplete: autoComplete ?? this.autoComplete,
applyHeightToFirstAscent:
applyHeightToFirstAscent ?? this.applyHeightToFirstAscent,
applyHeightToLastDescent:
applyHeightToLastDescent ?? this.applyHeightToLastDescent,
);
}
}
1 change: 1 addition & 0 deletions lib/src/editor/block_component/block_component.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// paragraph
export 'base_component/align_mixin.dart';
export 'base_component/auto_complete_command.dart';
export 'base_component/background_color_mixin.dart';
export 'base_component/block_component_action_wrapper.dart';
export 'base_component/block_component_configuration.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/editor/block_component/base_component/block_icon_builder.dart';
import 'package:flutter/material.dart';
import 'package:numerus/roman/roman.dart';
import 'package:provider/provider.dart';
Expand Down Expand Up @@ -40,13 +39,19 @@ Node numberedListNode({
);
}

typedef NumberedListIconBuilder = Widget Function(
BuildContext context,
Node node,
TextDirection direction,
);

class NumberedListBlockComponentBuilder extends BlockComponentBuilder {
NumberedListBlockComponentBuilder({
super.configuration,
this.iconBuilder,
});

final BlockIconBuilder? iconBuilder;
final NumberedListIconBuilder? iconBuilder;

@override
BlockComponentWidget build(BlockComponentContext blockComponentContext) {
Expand Down Expand Up @@ -78,7 +83,7 @@ class NumberedListBlockComponentWidget extends BlockComponentStatefulWidget {
this.iconBuilder,
});

final BlockIconBuilder? iconBuilder;
final NumberedListIconBuilder? iconBuilder;

@override
State<NumberedListBlockComponentWidget> createState() =>
Expand Down Expand Up @@ -131,7 +136,11 @@ class _NumberedListBlockComponentWidgetState
textDirection: textDirection,
children: [
widget.iconBuilder != null
? widget.iconBuilder!(context, node)
? widget.iconBuilder!(
context,
node,
textDirection,
)
: _NumberedListIcon(
node: node,
textStyle: textStyle,
Expand Down
Loading

0 comments on commit 9b31bdb

Please sign in to comment.