From f882d958d902f4848a0efb32f6f37e194cb3674e Mon Sep 17 00:00:00 2001 From: Lucas Date: Tue, 23 Dec 2025 15:12:57 +0800 Subject: [PATCH] feat: integrate awesome_lints and upgrade to Flutter 3.38 (#1173) * chore: update Flutter SDK to version 3.38.5 Upgrade Flutter from 3.32.4 to 3.38.5 to meet awesome_lints requirement for Dart SDK 3.10.0+. Update CI workflow to use the new Flutter version and add custom_lint verification step. * chore: integrate awesome_lints with custom lint rules Add awesome_lints and custom_lint dependencies, configure analysis_options.yaml to enable newline lint rules: newline_before_case, newline_before_constructor, newline_before_method, and newline_before_return. * style: apply newline formatting per awesome_lints rules Add blank lines before case clauses, return statements, method declarations, and constructors throughout the codebase to comply with awesome_lints newline rules. * fix: replace deprecated translate with leftTranslateByDouble Update Matrix4.translate() calls to use the new leftTranslateByDouble() API to resolve deprecation warnings in Flutter SDK 3.38.5. * chore: improve code readability with blank line formatting --- .fvmrc | 2 +- .github/workflows/test.yml | 3 +- analysis_options.yaml | 12 +++++- .../core/document/deprecated/document.dart | 7 ++++ lib/src/core/document/deprecated/node.dart | 11 ++++++ lib/src/core/document/diff.dart | 2 + lib/src/core/document/document.dart | 10 +++++ lib/src/core/document/node.dart | 15 +++++++ lib/src/core/document/node_iterator.dart | 4 ++ lib/src/core/document/path.dart | 11 ++++++ .../at_least_one_editable_node_rule.dart | 2 + lib/src/core/document/text_delta.dart | 27 +++++++++++++ lib/src/core/transform/operation.dart | 6 +++ lib/src/core/transform/transaction.dart | 9 +++++ .../base_component/align_mixin.dart | 3 ++ .../block_component_action_wrapper.dart | 2 + .../block_component_configuration.dart | 1 + .../convert_to_paragraph_command.dart | 1 + .../insert_newline_in_type_command.dart | 2 + .../markdown_format_helper.dart | 1 + .../selection/block_selection_area.dart | 3 ++ .../selection/block_selection_container.dart | 1 + .../remote_block_selection_area.dart | 3 ++ .../base_component/text_direction_mixin.dart | 2 + .../widget/full_screen_overlay_entry.dart | 2 + .../widget/ignore_parent_gesture.dart | 2 + .../bulleted_list_block_component.dart | 3 ++ .../divider_block_component.dart | 4 ++ .../divider_character_shortcut.dart | 1 + .../heading_block_component.dart | 4 ++ .../heading_character_shortcut.dart | 2 + .../image_block_component/base64_image.dart | 1 + .../image_block_component.dart | 7 ++++ .../resizable_image.dart | 2 + .../numbered_list_block_component.dart | 7 ++++ .../numbered_list_character_shortcut.dart | 1 + .../paragraph_block_component.dart | 1 + .../quote_block_component.dart | 3 ++ .../rich_text/appflowy_rich_text.dart | 22 +++++++++++ .../rich_text/default_selectable_mixin.dart | 3 ++ .../table_block_component/table_action.dart | 1 + .../table_block_component.dart | 9 +++++ .../table_cell_block_component.dart | 1 + .../table_block_component/table_commands.dart | 14 +++++++ .../table_block_component/table_node.dart | 5 +++ .../table_block_component/util.dart | 3 ++ .../todo_list_block_component.dart | 3 ++ .../todo_list_command_shortcut.dart | 2 + .../editor/command/selection_commands.dart | 7 ++++ lib/src/editor/command/text_commands.dart | 5 +++ .../entry/page_block_component.dart | 2 + .../service/editor_service.dart | 6 +++ .../ime/character_shortcut_event_helper.dart | 2 + .../ime/delta_input_on_delete_impl.dart | 1 + ...delta_input_on_floating_cursor_update.dart | 4 ++ .../ime/delta_input_on_insert_impl.dart | 1 + .../delta_input_on_non_text_update_impl.dart | 4 ++ .../ime/delta_input_on_replace_impl.dart | 1 + .../service/ime/delta_input_service.dart | 5 +++ .../service/ime/non_delta_input_service.dart | 8 ++++ .../service/ime/text_input_service.dart | 1 + .../service/keyboard_service_widget.dart | 15 +++++++ .../renderer/block_component_container.dart | 1 + .../renderer/block_component_service.dart | 1 + .../renderer/block_component_widget.dart | 1 + .../scroll/desktop_scroll_service.dart | 3 ++ .../scroll/editor_scroll_controller.dart | 5 +++ .../service/scroll/mobile_scroll_service.dart | 3 ++ .../service/scroll_service.dart | 1 + .../service/scroll_service_widget.dart | 2 + .../selection/desktop_selection_service.dart | 8 ++++ .../service/selection/mobile_magnifier.dart | 1 + .../selection/mobile_selection_service.dart | 20 ++++++++++ .../service/selection/shared.dart | 7 ++++ .../service/selection_service.dart | 3 ++ .../service/selection_service_widget.dart | 2 + .../format_double_characters.dart | 2 + .../format_single_character.dart | 8 ++++ .../shortcuts/character/slash_command.dart | 1 + .../shortcuts/command/arrow_down_command.dart | 1 + .../shortcuts/command/arrow_left_command.dart | 8 ++++ .../command/arrow_right_command.dart | 6 +++ .../shortcuts/command/arrow_up_command.dart | 2 + .../shortcuts/command/backspace_command.dart | 3 ++ .../command/copy_paste_extension.dart | 4 ++ .../shortcuts/command/cut_command.dart | 1 + .../shortcuts/command/delete_command.dart | 3 ++ .../shortcuts/command/end_command.dart | 1 + .../shortcuts/command/escape_command.dart | 1 + .../shortcuts/command/home_command.dart | 1 + .../shortcuts/command/page_down_command.dart | 1 + .../shortcuts/command/page_up_command.dart | 2 + .../shortcuts/command/paste_command.dart | 3 ++ .../command/remove_line_command.dart | 1 + .../shortcuts/command/select_all_command.dart | 1 + .../command/show_link_menu_command.dart | 1 + .../command/toggle_colors_command.dart | 1 + .../shortcuts/command/undo_redo_command.dart | 2 + ...ult_text_span_decorator_for_attribute.dart | 2 + ...ile_text_span_decorator_for_attribute.dart | 4 ++ .../find_replace_menu/find_menu_service.dart | 2 + .../find_replace_widget.dart | 3 ++ .../find_replace_menu/search_algorithm.dart | 1 + .../find_replace_menu/search_service_v2.dart | 5 +++ .../find_replace_menu/search_service_v3.dart | 8 ++++ .../selection_menu_item_widget.dart | 1 + .../selection_menu_service.dart | 5 +++ .../selection_menu/selection_menu_widget.dart | 12 ++++++ .../toolbar/desktop/floating_toolbar.dart | 3 ++ .../desktop/floating_toolbar_widget.dart | 2 + .../desktop/items/color/color_picker.dart | 5 +++ .../color/highlight_color_toolbar_item.dart | 2 + .../items/color/text_color_toolbar_item.dart | 2 + .../desktop/items/heading_toolbar_items.dart | 1 + .../toolbar/desktop/items/link/link_menu.dart | 1 + .../desktop/items/utils/overlay_util.dart | 1 + .../desktop/items/utils/tooltip_util.dart | 12 ++++++ .../mobile_floating_toolbar.dart | 1 + .../editor/toolbar/mobile/mobile_toolbar.dart | 2 + .../toolbar/mobile/mobile_toolbar_v2.dart | 4 ++ .../blocks_mobile_toolbar_item.dart | 1 + .../background_color_options_widgets.dart | 1 + ...xt_and_background_color_tool_bar_item.dart | 1 + .../color/text_color_options_widgets.dart | 1 + .../color/utils/clear_color_button.dart | 1 + .../color/utils/color_button.dart | 1 + .../heading_mobile_toolbar_item.dart | 1 + .../link_mobile_toolbar_item.dart | 1 + .../list_mobile_toolbar_item.dart | 2 + .../text_decoration_mobile_toolbar_item.dart | 2 + ...ext_decoration_mobile_toolbar_item_v2.dart | 1 + .../utils/mobile_toolbar_item_menu_btn.dart | 2 + .../mobile_toolbar_menu_grid_delegate.dart | 2 + lib/src/editor/util/delta_util.dart | 1 + .../editor_state_selectable_extension.dart | 2 + .../util/file_picker/file_picker_impl.dart | 1 + lib/src/editor/util/link_util.dart | 1 + lib/src/editor/util/platform_extension.dart | 3 ++ lib/src/editor/util/property_notifier.dart | 1 + lib/src/editor/util/text_direction.dart | 1 + lib/src/editor_state.dart | 4 ++ lib/src/extensions/alignment_extension.dart | 1 + lib/src/extensions/attributes_extension.dart | 3 ++ lib/src/extensions/node_extensions.dart | 12 +++++- lib/src/extensions/object_extensions.dart | 1 + lib/src/extensions/position_extension.dart | 5 +++ lib/src/extensions/text_style_extension.dart | 2 + lib/src/extensions/theme_extension.dart | 1 + .../extensions/url_launcher_extension.dart | 1 + lib/src/flutter/overlay.dart | 18 +++++++++ lib/src/flutter/scrollable_helpers.dart | 13 +++++++ .../src/positioned_list.dart | 1 + .../src/scroll_view.dart | 1 + .../src/scrollable_positioned_list.dart | 3 ++ .../src/viewport.dart | 7 ++++ .../src/wrapping.dart | 25 +++++++++++- lib/src/history/undo_manager.dart | 4 ++ lib/src/infra/clipboard.dart | 1 + lib/src/infra/flowy_svg.dart | 3 ++ lib/src/infra/log.dart | 15 +++++++ .../columns/column_block_component.dart | 3 ++ .../columns/columns_block_component.dart | 4 ++ .../html/encoder/delta_html_encoder.dart | 2 + .../parser/bulleted_list_node_parser.dart | 1 + .../encoder/parser/heading_node_parser.dart | 1 + .../html/encoder/parser/html_node_parser.dart | 2 + .../parser/numbered_list_node_parser.dart | 1 + .../encoder/parser/quote_node_parser.dart | 1 + .../encoder/parser/table_node_parser.dart | 1 + .../html/encoder/parser/text_node_parser.dart | 1 + .../encoder/parser/todo_list_node_parser.dart | 1 + .../plugins/html/html_document_decoder.dart | 35 +++++++++++++++++ .../plugins/html/html_document_encoder.dart | 1 + .../custom_syntaxes/formula_syntax.dart | 1 + .../custom_syntaxes/underline_syntax.dart | 1 + .../decoder/delta_markdown_decoder.dart | 3 ++ .../decoder/document_markdown_decoder.dart | 1 + .../parser/markdown_block_quote_parser.dart | 1 + .../parser/markdown_heading_parser.dart | 1 + .../parser/markdown_paragraph_parser.dart | 2 + .../parser/markdown_todo_list_parser.dart | 1 + .../encoder/delta_markdown_encoder.dart | 1 + .../encoder/document_markdown_encoder.dart | 2 + .../parser/bulleted_list_node_parser.dart | 1 + .../markdown/encoder/parser/node_parser.dart | 1 + .../parser/numbered_list_node_parser.dart | 1 + .../encoder/parser/quote_node_parser.dart | 1 + .../encoder/parser/text_node_parser.dart | 1 + .../encoder/parser/todo_list_node_parser.dart | 1 + lib/src/plugins/pdf/html_to_pdf_encoder.dart | 39 +++++++++++++++++++ .../quill_delta/quill_delta_encoder.dart | 11 ++++++ .../word_count/word_counter_service.dart | 3 ++ lib/src/render/color_menu/color_picker.dart | 5 +++ lib/src/render/selection/cursor.dart | 2 + .../render/selection/mobile_basic_handle.dart | 9 +++++ .../selection/mobile_collapsed_handle.dart | 2 + lib/src/render/selection/selectable.dart | 1 + lib/src/render/toolbar/toolbar_item.dart | 3 ++ .../render/toolbar/toolbar_item_widget.dart | 1 + .../format_rich_text_style.dart | 1 + .../copy_paste_handler.dart | 8 ++++ .../exit_editing_mode_handler.dart | 1 + .../page_up_down_handler.dart | 2 + .../redo_undo_handler.dart | 2 + .../service/shortcut_event/keybinding.dart | 1 + pubspec.yaml | 5 +++ test/core/document/diff_test.dart | 1 + test/customer/auto_complete_test.dart | 1 + .../custom_attribute_for_text_block_test.dart | 2 + test/customer/custom_block_icon_test.dart | 1 + .../custom_editor_directionality_test.dart | 1 + test/customer/custom_error_block_test.dart | 1 + test/customer/custom_image_menu_test.dart | 1 + .../ime/non_delta_input_service_test.dart | 4 ++ test/editor_state_test.dart | 1 + test/infra/clipboard_test.dart | 2 + .../mobile_app_with_toolbar_widget.dart | 1 + test/new/command/text_commands_test.dart | 2 + test/new/extensions/node_extension_test.dart | 5 +++ test/new/infra/testable_editor.dart | 4 ++ .../character_shortcut_event_test.dart | 1 + .../copy_command_test.dart | 2 + .../copy_paste_handler_test.dart | 2 + .../paste_command_test.dart | 2 + test/new/util/document_util.dart | 2 + test/new/util/node_util.dart | 1 + test/plugins/html/html_document_test.dart | 1 + .../test_custom_node_parsers.dart | 1 + test/service/context_menu_test.dart | 2 + 229 files changed, 850 insertions(+), 5 deletions(-) diff --git a/.fvmrc b/.fvmrc index 984aec1c..f6203263 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.32.4" + "flutter": "3.38.5" } \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fb1845f6..a8e95588 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: "stable" - flutter-version: "3.32.4" + flutter-version: "3.38.5" cache: true - name: Run tests @@ -42,6 +42,7 @@ jobs: flutter pub get flutter analyze . dart format --set-exit-if-changed . + dart run custom_lint flutter test --coverage - name: Upload coverage to Codecov diff --git a/analysis_options.yaml b/analysis_options.yaml index 9a3c1f31..e6c39295 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,4 +11,14 @@ linter: analyzer: exclude: - - lib/src/l10n/** \ No newline at end of file + - lib/src/l10n/** + plugins: + - custom_lint + +custom_lint: + enable_all_lint_rules: false + rules: + - newline_before_case + - newline_before_constructor + - newline_before_method + - newline_before_return diff --git a/lib/src/core/document/deprecated/document.dart b/lib/src/core/document/deprecated/document.dart index e89dbdb1..b0084f3e 100644 --- a/lib/src/core/document/deprecated/document.dart +++ b/lib/src/core/document/deprecated/document.dart @@ -22,6 +22,7 @@ class DocumentV0 { final document = Map.from(json['document'] as Map); final root = NodeV0.fromJson(document); + return DocumentV0(root: root); } @@ -31,6 +32,7 @@ class DocumentV0 { type: 'editor', children: LinkedList()..add(TextNodeV0.empty()), ); + return DocumentV0( root: root, ); @@ -54,6 +56,7 @@ class DocumentV0 { for (final node in nodes) { target.insertBefore(node); } + return true; } @@ -62,6 +65,7 @@ class DocumentV0 { for (var i = 0; i < nodes.length; i++) { parent.insert(nodes.elementAt(i), index: path.last + i); } + return true; } @@ -83,6 +87,7 @@ class DocumentV0 { target = next; length--; } + return true; } @@ -96,6 +101,7 @@ class DocumentV0 { return false; } target.updateAttributes(attributes); + return true; } @@ -109,6 +115,7 @@ class DocumentV0 { return false; } target.delta = target.delta.compose(delta); + return true; } diff --git a/lib/src/core/document/deprecated/node.dart b/lib/src/core/document/deprecated/node.dart index c32d94aa..ba541485 100644 --- a/lib/src/core/document/deprecated/node.dart +++ b/lib/src/core/document/deprecated/node.dart @@ -87,6 +87,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { if (subtype != null) { return '$type/$subtype'; } + return type; } @@ -94,6 +95,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { if (attributes[BuiltInAttributeKey.subtype] is String) { return attributes[BuiltInAttributeKey.subtype] as String; } + return null; } @@ -136,6 +138,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { entry.parent = this; children.add(entry); notifyListeners(); + return; } @@ -188,6 +191,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { if (attributes.isNotEmpty) { map['attributes'] = attributes; } + return map; } @@ -208,6 +212,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { ); } } + return node; } @@ -222,6 +227,7 @@ final class NodeV0 extends ChangeNotifier with LinkedListEntry { } index += 1; } + return parent!._computePath([index, ...previous]); } } @@ -245,7 +251,9 @@ final class TextNodeV0 extends NodeV0 { ); Delta _delta; + Delta get delta => _delta; + set delta(Delta v) { _delta = v; notifyListeners(); @@ -255,6 +263,7 @@ final class TextNodeV0 extends NodeV0 { Map toJson() { final map = super.toJson(); map['delta'] = delta.toJson(); + return map; } @@ -277,6 +286,7 @@ final class TextNodeV0 extends NodeV0 { ); } } + return textNode; } @@ -293,6 +303,7 @@ extension NodeV0Equality on Iterable { return false; } } + return true; } diff --git a/lib/src/core/document/diff.dart b/lib/src/core/document/diff.dart index 11684bf8..93b6780f 100644 --- a/lib/src/core/document/diff.dart +++ b/lib/src/core/document/diff.dart @@ -71,6 +71,7 @@ List diffNodes(Node oldNode, Node newNode) { } } } + return combinedOperations; } @@ -99,6 +100,7 @@ List diffNodes(Node oldNode, Node newNode) { } } } + return combinedOperations; } diff --git a/lib/src/core/document/document.dart b/lib/src/core/document/document.dart index 890a5fda..9cee13cc 100644 --- a/lib/src/core/document/document.dart +++ b/lib/src/core/document/document.dart @@ -41,6 +41,7 @@ class Document { final document = Map.from(json['document'] as Map); final root = Node.fromJson(document); + return Document(root: root); } @@ -51,6 +52,7 @@ class Document { type: 'document', children: LinkedList()..add(TextNode.empty()), ); + return Document( root: root, ); @@ -66,6 +68,7 @@ class Document { type: 'page', children: withInitialText ? [paragraphNode()] : [], ); + return Document( root: root, ); @@ -83,6 +86,7 @@ class Document { while (current != null && current.children.isNotEmpty) { current = current.children.last; } + return current; } @@ -110,6 +114,7 @@ class Document { for (final node in nodes) { target.insertBefore(node); } + return true; } @@ -118,6 +123,7 @@ class Document { for (var i = 0; i < nodes.length; i++) { parent.insert(nodes.elementAt(i), index: path.last + i); } + return true; } @@ -139,6 +145,7 @@ class Document { target = next; length--; } + return true; } @@ -147,6 +154,7 @@ class Document { // if the path is empty, it means the root node. if (path.isEmpty) { root.updateAttributes(attributes); + return true; } final target = nodeAtPath(path); @@ -154,6 +162,7 @@ class Document { return false; } target.updateAttributes(attributes); + return true; } @@ -168,6 +177,7 @@ class Document { return false; } target.updateAttributes({'delta': (targetDelta.compose(delta)).toJson()}); + return true; } diff --git a/lib/src/core/document/node.dart b/lib/src/core/document/node.dart index 1a390658..76c8da4f 100644 --- a/lib/src/core/document/node.dart +++ b/lib/src/core/document/node.dart @@ -84,8 +84,10 @@ final class Node extends ChangeNotifier with LinkedListEntry { /// The children of the node. final LinkedList _children; + List get children { _cacheChildren ??= _children.toList(growable: false); + return _cacheChildren!; } @@ -93,6 +95,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { /// The attributes of the node. Attributes _attributes; + Attributes get attributes => {..._attributes}; /// The path of the node. @@ -138,6 +141,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { final index = path.first; final child = childAtIndexOrNull(index); + return child?.childAtPath(path.sublist(1)); } @@ -161,6 +165,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { if (_children.isEmpty) { _children.add(entry); notifyListeners(); + return; } @@ -213,6 +218,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { parent?.notifyListeners(); parent = null; + return true; } @@ -235,6 +241,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { if (attributes['delta'] is List) { return Delta.fromJson(attributes['delta']); } + return null; } @@ -253,6 +260,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { // filter the null value map['data'] = attributes..removeWhere((_, value) => value == null); } + return map; } @@ -281,6 +289,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { } node.externalValues = externalValues; node.extraInfos = extraInfos; + return node; } @@ -297,6 +306,7 @@ final class Node extends ChangeNotifier with LinkedListEntry { return previous; } final index = parent.children.indexOf(this); + return parent._computePath([index, ...previous]); } @@ -351,8 +361,10 @@ final class TextNode extends Node { String get subtype => ''; Delta _delta; + @override Delta get delta => _delta; + set delta(Delta v) { _delta = v; notifyListeners(); @@ -362,6 +374,7 @@ final class TextNode extends Node { Map toJson() { final map = super.toJson(); map['delta'] = delta.toJson(); + return map; } @@ -385,6 +398,7 @@ final class TextNode extends Node { ); } } + return textNode; } @@ -401,6 +415,7 @@ extension NodeEquality on Iterable { return false; } } + return true; } diff --git a/lib/src/core/document/node_iterator.dart b/lib/src/core/document/node_iterator.dart index 2b99f7d4..0a2e4e06 100644 --- a/lib/src/core/document/node_iterator.dart +++ b/lib/src/core/document/node_iterator.dart @@ -30,6 +30,7 @@ class NodeIterator implements Iterator { if (!_began) { _currentNode = startNode; _began = true; + return true; } @@ -40,6 +41,7 @@ class NodeIterator implements Iterator { if (endNode != null && endNode == node) { _currentNode = null; + return false; } @@ -49,6 +51,7 @@ class NodeIterator implements Iterator { _currentNode = node.next!; } else if (node.parent == null) { _currentNode = null; + return false; } else { while (node.parent != null) { @@ -74,6 +77,7 @@ class NodeIterator implements Iterator { while (moveNext()) { result.add(current); } + return result; } } diff --git a/lib/src/core/document/path.dart b/lib/src/core/document/path.dart index bf54a0eb..3a1238d5 100644 --- a/lib/src/core/document/path.dart +++ b/lib/src/core/document/path.dart @@ -14,6 +14,7 @@ extension PathExtensions on Path { if (equals(other)) { return true; } + return this > other; } @@ -32,6 +33,7 @@ extension PathExtensions on Path { if (this.length < other.length) { return false; } + return true; } @@ -39,6 +41,7 @@ extension PathExtensions on Path { if (equals(other)) { return true; } + return this < other; } @@ -57,6 +60,7 @@ extension PathExtensions on Path { if (this.length > other.length) { return false; } + return true; } @@ -66,6 +70,7 @@ extension PathExtensions on Path { return nextPath; } final last = nextPath.last; + return nextPath ..removeLast() ..add(last + 1); @@ -77,6 +82,7 @@ extension PathExtensions on Path { return nextPath; } final last = nextPath.last; + return nextPath ..removeLast() ..add(last + n); @@ -92,6 +98,7 @@ extension PathExtensions on Path { return previousPath; } final last = previousPath.last; + return previousPath ..removeLast() ..add(max(0, last - 1)); @@ -103,6 +110,7 @@ extension PathExtensions on Path { return previousPath; } final last = previousPath.last; + return previousPath ..removeLast() ..add(max(0, last - n)); @@ -112,6 +120,7 @@ extension PathExtensions on Path { if (isEmpty) { return this; } + return Path.from(this, growable: true)..removeLast(); } @@ -130,6 +139,7 @@ extension PathExtensions on Path { return false; } } + return true; } @@ -145,6 +155,7 @@ extension PathExtensions on Path { if (isSameDepth) { return result && selection.start.path.length == length; } + return result; } } diff --git a/lib/src/core/document/rules/at_least_one_editable_node_rule.dart b/lib/src/core/document/rules/at_least_one_editable_node_rule.dart index acd1aea0..8f113af6 100644 --- a/lib/src/core/document/rules/at_least_one_editable_node_rule.dart +++ b/lib/src/core/document/rules/at_least_one_editable_node_rule.dart @@ -5,6 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart'; /// If the document is empty, it will create a new paragraph node. class AtLeastOneEditableNodeRule extends DocumentRule { const AtLeastOneEditableNodeRule(); + @override bool shouldApply({ required EditorState editorState, @@ -15,6 +16,7 @@ class AtLeastOneEditableNodeRule extends DocumentRule { return false; } final document = editorState.document; + return document.root.children.isEmpty; } diff --git a/lib/src/core/document/text_delta.dart b/lib/src/core/document/text_delta.dart index 2be88533..9f153ec9 100644 --- a/lib/src/core/document/text_delta.dart +++ b/lib/src/core/document/text_delta.dart @@ -131,6 +131,7 @@ class TextInsert extends TextOperation { if (_attributes != null && _attributes.isNotEmpty) { result['attributes'] = attributes; } + return result; } @@ -168,6 +169,7 @@ class TextRetain extends TextOperation { if (_attributes != null && _attributes.isNotEmpty) { result['attributes'] = attributes; } + return result; } @@ -256,11 +258,13 @@ class Delta extends Iterable { final lastOp = _operations.last; if (lastOp is TextDelete && textOperation is TextDelete) { lastOp.length += textOperation.length; + return; } if (_mapEquals(lastOp.attributes, textOperation.attributes)) { if (lastOp is TextInsert && textOperation is TextInsert) { lastOp.text += textOperation.text; + return; } // if there is an delete before the insert @@ -269,10 +273,12 @@ class Delta extends Iterable { _operations.removeLast(); _operations.add(textOperation); _operations.add(lastOp); + return; } if (lastOp is TextRetain && textOperation is TextRetain) { lastOp.length += textOperation.length; + return; } } @@ -387,6 +393,7 @@ class Delta extends Iterable { delta._operations.isNotEmpty && delta._operations.last == newOp) { final rest = Delta(operations: thisIter.rest()); + return (delta + rest)..chop(); } } else if (otherOp is TextDelete && (thisOp is TextRetain)) { @@ -409,8 +416,10 @@ class Delta extends Iterable { return op.text; } assert(false, 'diff() called with non-insert operations'); + return ''; }).join(); + return text; }).toList(); @@ -430,11 +439,13 @@ class Delta extends Iterable { opLength = min(otherIter.peekLength(), length); retDelta.add(otherIter.next(opLength)); break; + case diff_match_patch.DIFF_DELETE: opLength = min(length, thisIter.peekLength()); thisIter.next(opLength); retDelta.delete(opLength); break; + case diff_match_patch.DIFF_EQUAL: opLength = min( min(thisIter.peekLength(), otherIter.peekLength()), @@ -460,6 +471,7 @@ class Delta extends Iterable { length -= opLength; } } + return retDelta..trim(); } @@ -480,6 +492,7 @@ class Delta extends Iterable { operations.add(other._operations[0]); operations.addAll(other._operations.sublist(1)); } + return Delta(operations: operations); } @@ -499,6 +512,7 @@ class Delta extends Iterable { if (other is! Delta) { return false; } + return listEquals(_operations, other._operations); } @@ -515,6 +529,7 @@ class Delta extends Iterable { inverted.delete(op.length); } else if (op is TextRetain && op.attributes == null) { inverted.retain(op.length); + return previousValue + op.length; } else if (op is TextDelete || op is TextRetain) { final length = op.length; @@ -529,10 +544,13 @@ class Delta extends Iterable { ); } } + return previousValue + length; } + return previousValue; }); + return inverted..chop(); } @@ -554,6 +572,7 @@ class Delta extends Iterable { final content = toPlainText(); final boundary = CharacterBoundary(content); final index = boundary.getLeadingTextBoundaryAt(pos - 1); + return index ?? 0; } @@ -571,12 +590,14 @@ class Delta extends Iterable { } final boundary = CharacterBoundary(content); final index = boundary.getTrailingTextBoundaryAt(pos); + return index ?? content.length; } String toPlainText() { _plainText ??= _operations.whereType().map((op) => op.text).join(); + return _plainText!; } @@ -634,8 +655,10 @@ class _OpIterator { int peekLength() { if (_index < _operations.length) { final op = _operations[_index]; + return op.length - _offset; } + return _maxInt; } @@ -661,8 +684,10 @@ class _OpIterator { switch (nextOp) { case TextDelete _: return TextDelete(length: length); + case TextRetain _: return TextRetain(length, attributes: nextOp.attributes); + case TextInsert _: return TextInsert( nextOp.text.substring(offset, offset + length), @@ -683,6 +708,7 @@ class _OpIterator { final rest = _operations.sublist(_index); _offset = offset; _index = index; + return [next] + rest; } } @@ -692,5 +718,6 @@ bool _mapEquals(Map? a, Map? b) { if ((a == null || a.isEmpty) && (b == null || b.isEmpty)) { return true; } + return mapEquals(a, b); } diff --git a/lib/src/core/transform/operation.dart b/lib/src/core/transform/operation.dart index 87cb4412..723a6f68 100644 --- a/lib/src/core/transform/operation.dart +++ b/lib/src/core/transform/operation.dart @@ -34,6 +34,7 @@ class InsertOperation extends Operation { final nodes = (json['nodes'] as List) .map((n) => Node.fromJson(n)) .toList(growable: false); + return InsertOperation(path, nodes); } @@ -81,6 +82,7 @@ class DeleteOperation extends Operation { final nodes = (json['nodes'] as List) .map((n) => Node.fromJson(n)) .toList(growable: false); + return DeleteOperation(path, nodes); } @@ -128,6 +130,7 @@ class UpdateOperation extends Operation { final path = json['path'] as Path; final oldAttributes = json['oldAttributes'] as Attributes; final attributes = json['attributes'] as Attributes; + return UpdateOperation( path, attributes, @@ -191,6 +194,7 @@ class UpdateTextOperation extends Operation { final path = json['path'] as Path; final delta = Delta.fromJson(json['delta']); final inverted = Delta.fromJson(json['inverted']); + return UpdateTextOperation(path, delta, inverted); } @@ -255,6 +259,7 @@ Path transformPath(Path preInsertPath, Path b, [int delta = 1]) { Operation? transformOperation(Operation a, Operation b) { if (a is InsertOperation) { final newPath = transformPath(a.path, b.path, a.nodes.length); + return b.copyWith(path: newPath); } else if (a is DeleteOperation) { if (b is DeleteOperation) { @@ -265,6 +270,7 @@ Operation? transformOperation(Operation a, Operation b) { } } final newPath = transformPath(a.path, b.path, -1 * a.nodes.length); + return b.copyWith(path: newPath); } diff --git a/lib/src/core/transform/transaction.dart b/lib/src/core/transform/transaction.dart index e3a86ff1..f1f5a01b 100644 --- a/lib/src/core/transform/transaction.dart +++ b/lib/src/core/transform/transaction.dart @@ -22,6 +22,7 @@ class Transaction { compose(); markNeedsComposing = false; } + return _operations; } @@ -144,6 +145,7 @@ class Transaction { if (beforeSelection != null) { json['before_selection'] = beforeSelection!.toJson(); } + return json; } @@ -165,6 +167,7 @@ class Transaction { op.inverted.compose(last.inverted), ); operations[_operations.length - 1] = newOp; + return; } } @@ -208,12 +211,14 @@ extension TextTransaction on Transaction { final delta = node.delta; if (delta == null) { assert(false, 'The node must have a delta.'); + return; } if (index < 0 || index > delta.length) { AppFlowyEditorLog.editor .info('The index($index) is out of range or negative.'); + return; } @@ -244,6 +249,7 @@ extension TextTransaction on Transaction { final delta = node.delta; if (delta == null) { assert(false, 'The node must have a delta.'); + return; } @@ -272,6 +278,7 @@ extension TextTransaction on Transaction { final delta = node.delta; if (delta == null) { assert(false, 'The node must have a delta.'); + return; } @@ -416,6 +423,7 @@ extension TextTransaction on Transaction { void compose() { if (_composeMap.isEmpty) { markNeedsComposing = false; + return; } for (final entry in _composeMap.entries) { @@ -460,6 +468,7 @@ extension TextTransaction on Transaction { selection.endIndex - selection.startIndex, texts.first, ); + return; } diff --git a/lib/src/editor/block_component/base_component/align_mixin.dart b/lib/src/editor/block_component/base_component/align_mixin.dart index 549d9d96..516d534d 100644 --- a/lib/src/editor/block_component/base_component/align_mixin.dart +++ b/lib/src/editor/block_component/base_component/align_mixin.dart @@ -9,10 +9,13 @@ mixin BlockComponentAlignMixin { switch (alignString) { case 'center': return Alignment.center; + case 'right': return Alignment.centerRight; + case 'left': return Alignment.centerLeft; + default: return null; } diff --git a/lib/src/editor/block_component/base_component/block_component_action_wrapper.dart b/lib/src/editor/block_component/base_component/block_component_action_wrapper.dart index ac6f0c73..4af7c689 100644 --- a/lib/src/editor/block_component/base_component/block_component_action_wrapper.dart +++ b/lib/src/editor/block_component/base_component/block_component_action_wrapper.dart @@ -39,7 +39,9 @@ class _BlockComponentActionWrapperState bool isDisposed = false; bool _alwaysShowActions = false; + bool get alwaysShowActions => _alwaysShowActions; + @override set alwaysShowActions(bool alwaysShowActions) { if (isDisposed) { diff --git a/lib/src/editor/block_component/base_component/block_component_configuration.dart b/lib/src/editor/block_component/base_component/block_component_configuration.dart index c581e08b..ff4a7f83 100644 --- a/lib/src/editor/block_component/base_component/block_component_configuration.dart +++ b/lib/src/editor/block_component/base_component/block_component_configuration.dart @@ -98,6 +98,7 @@ EdgeInsets _indentPadding(Node node, TextDirection textDirection) { switch (textDirection) { case TextDirection.ltr: return const EdgeInsets.only(left: 24.0); + case TextDirection.rtl: return const EdgeInsets.only(right: 24.0); } diff --git a/lib/src/editor/block_component/base_component/convert_to_paragraph_command.dart b/lib/src/editor/block_component/base_component/convert_to_paragraph_command.dart index 18152236..cad54b2e 100644 --- a/lib/src/editor/block_component/base_component/convert_to_paragraph_command.dart +++ b/lib/src/editor/block_component/base_component/convert_to_paragraph_command.dart @@ -57,5 +57,6 @@ CommandShortcutEventHandler _convertToParagraphCommandHandler = (editorState) { ..deleteNode(node) ..afterSelection = transaction.beforeSelection; editorState.apply(transaction); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/block_component/base_component/insert_newline_in_type_command.dart b/lib/src/editor/block_component/base_component/insert_newline_in_type_command.dart index f5219a22..175ba603 100644 --- a/lib/src/editor/block_component/base_component/insert_newline_in_type_command.dart +++ b/lib/src/editor/block_component/base_component/insert_newline_in_type_command.dart @@ -29,6 +29,7 @@ Future insertNewLineInType( if (node != null && node.path.length > 1) { return KeyEventResult.ignored != outdentCommand.execute(editorState); } + return KeyEventResult.ignored != convertToParagraphCommand.execute(editorState); } @@ -42,5 +43,6 @@ Future insertNewLineInType( }, ), ); + return true; } diff --git a/lib/src/editor/block_component/base_component/markdown_format_helper.dart b/lib/src/editor/block_component/base_component/markdown_format_helper.dart index 12584521..d71c8d48 100644 --- a/lib/src/editor/block_component/base_component/markdown_format_helper.dart +++ b/lib/src/editor/block_component/base_component/markdown_format_helper.dart @@ -72,5 +72,6 @@ Future formatMarkdownSymbol( ..afterSelection = afterSelection; await editorState.apply(transaction); + return true; } diff --git a/lib/src/editor/block_component/base_component/selection/block_selection_area.dart b/lib/src/editor/block_component/base_component/selection/block_selection_area.dart index 8508a1b2..31de6ef0 100644 --- a/lib/src/editor/block_component/base_component/selection/block_selection_area.dart +++ b/lib/src/editor/block_component/base_component/selection/block_selection_area.dart @@ -114,6 +114,7 @@ class _BlockSelectionAreaState extends State { final padding = builder?.configuration.blockSelectionAreaMargin( widget.node, ); + return Positioned.fromRect( rect: prevBlockRect!, child: Container( @@ -145,6 +146,7 @@ class _BlockSelectionAreaState extends State { ); // force to show the cursor cursorKey.currentState?.unwrapOrNull()?.show(); + return cursor; } else { // show the selection area when the selection is not collapsed @@ -155,6 +157,7 @@ class _BlockSelectionAreaState extends State { prevSelectionRects!.first.width == 0)) { return sizedBox; } + return SelectionAreaPaint( rects: prevSelectionRects!, selectionColor: widget.selectionColor, diff --git a/lib/src/editor/block_component/base_component/selection/block_selection_container.dart b/lib/src/editor/block_component/base_component/selection/block_selection_container.dart index 0a669f7f..1250d468 100644 --- a/lib/src/editor/block_component/base_component/selection/block_selection_container.dart +++ b/lib/src/editor/block_component/base_component/selection/block_selection_container.dart @@ -63,6 +63,7 @@ class BlockSelectionContainer extends StatelessWidget { ) .toList(), ); + return Stack( clipBehavior: Clip.none, // In RTL mode, if the alignment is topStart, diff --git a/lib/src/editor/block_component/base_component/selection/remote_block_selection_area.dart b/lib/src/editor/block_component/base_component/selection/remote_block_selection_area.dart index d21db7ce..a9021253 100644 --- a/lib/src/editor/block_component/base_component/selection/remote_block_selection_area.dart +++ b/lib/src/editor/block_component/base_component/selection/remote_block_selection_area.dart @@ -41,6 +41,7 @@ class RemoteBlockSelectionsArea extends StatelessWidget { if (selections.isEmpty) { return child; } + return Positioned.fill( child: Stack( children: selections @@ -134,6 +135,7 @@ class _RemoteBlockSelectionAreaState extends State { child, ], ); + return cursor; } else { // show the selection area when the selection is not collapsed @@ -144,6 +146,7 @@ class _RemoteBlockSelectionAreaState extends State { prevSelectionRects!.first.width == 0)) { return child; } + return Stack( clipBehavior: Clip.none, children: [ diff --git a/lib/src/editor/block_component/base_component/text_direction_mixin.dart b/lib/src/editor/block_component/base_component/text_direction_mixin.dart index 37c6a842..8698f2b7 100644 --- a/lib/src/editor/block_component/base_component/text_direction_mixin.dart +++ b/lib/src/editor/block_component/base_component/text_direction_mixin.dart @@ -110,6 +110,7 @@ TextDirection? _getDirectionFromPreviousOrParentNode( defaultTextDirection, ); } + return prevOrParentNodeDirection; } @@ -138,6 +139,7 @@ extension on String { } else if (this == blockComponentTextDirectionRTL) { return TextDirection.rtl; } + return null; } } diff --git a/lib/src/editor/block_component/base_component/widget/full_screen_overlay_entry.dart b/lib/src/editor/block_component/base_component/widget/full_screen_overlay_entry.dart index c5ed7861..f6786cfd 100644 --- a/lib/src/editor/block_component/base_component/widget/full_screen_overlay_entry.dart +++ b/lib/src/editor/block_component/base_component/widget/full_screen_overlay_entry.dart @@ -26,6 +26,7 @@ class FullScreenOverlayEntry { _entry = OverlayEntry( builder: (context) { final size = MediaQuery.of(context).size; + return SizedBox.fromSize( size: size, child: Stack( @@ -57,6 +58,7 @@ class FullScreenOverlayEntry { ); }, ); + return _entry!; } } diff --git a/lib/src/editor/block_component/base_component/widget/ignore_parent_gesture.dart b/lib/src/editor/block_component/base_component/widget/ignore_parent_gesture.dart index d37193e4..b4079271 100644 --- a/lib/src/editor/block_component/base_component/widget/ignore_parent_gesture.dart +++ b/lib/src/editor/block_component/base_component/widget/ignore_parent_gesture.dart @@ -33,8 +33,10 @@ class _IgnoreEditorSelectionGestureState final renderObject = context.findRenderObject(); if (renderObject != null && renderObject is RenderBox) { final offset = renderObject.globalToLocal(details.globalPosition); + return !renderObject.paintBounds.contains(offset); } + return true; }, ); diff --git a/lib/src/editor/block_component/bulleted_list_block_component/bulleted_list_block_component.dart b/lib/src/editor/block_component/bulleted_list_block_component/bulleted_list_block_component.dart index d2831269..ece9679d 100644 --- a/lib/src/editor/block_component/bulleted_list_block_component/bulleted_list_block_component.dart +++ b/lib/src/editor/block_component/bulleted_list_block_component/bulleted_list_block_component.dart @@ -46,6 +46,7 @@ class BulletedListBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return BulletedListBlockComponentWidget( key: node.key, node: node, @@ -217,6 +218,7 @@ class _BulletedListIcon extends StatelessWidget { } parent = parent.parent; } + return level; } @@ -226,6 +228,7 @@ class _BulletedListIcon extends StatelessWidget { Widget build(BuildContext context) { final textScaleFactor = context.read().editorStyle.textScaleFactor; + return Container( constraints: const BoxConstraints(minWidth: 26, minHeight: 22) * textScaleFactor, diff --git a/lib/src/editor/block_component/divider_block_component/divider_block_component.dart b/lib/src/editor/block_component/divider_block_component/divider_block_component.dart index cc7f79af..c11b21aa 100644 --- a/lib/src/editor/block_component/divider_block_component/divider_block_component.dart +++ b/lib/src/editor/block_component/divider_block_component/divider_block_component.dart @@ -36,6 +36,7 @@ class DividerBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return DividerBlockComponentWidget( key: node.key, node: node, @@ -91,6 +92,7 @@ class _DividerBlockComponentWidgetState Node get node => widget.node; final dividerKey = GlobalKey(); + RenderBox? get _renderBox => context.findRenderObject() as RenderBox?; @override @@ -174,6 +176,7 @@ class _DividerBlockComponentWidgetState if (_renderBox == null) { return null; } + return getRectsInSelection( Selection.collapsed(position), shiftWithBaseOffset: shiftWithBaseOffset, @@ -198,6 +201,7 @@ class _DividerBlockComponentWidgetState dividerBox.size, ]; } + return [Offset.zero & _renderBox!.size]; } diff --git a/lib/src/editor/block_component/divider_block_component/divider_character_shortcut.dart b/lib/src/editor/block_component/divider_block_component/divider_character_shortcut.dart index 95deebe9..49122b59 100644 --- a/lib/src/editor/block_component/divider_block_component/divider_character_shortcut.dart +++ b/lib/src/editor/block_component/divider_block_component/divider_character_shortcut.dart @@ -52,5 +52,6 @@ Future _convertSyntaxToDivider( ..deleteNode(node) ..afterSelection = Selection.collapsed(Position(path: path.next)); editorState.apply(transaction); + return true; } diff --git a/lib/src/editor/block_component/heading_block_component/heading_block_component.dart b/lib/src/editor/block_component/heading_block_component/heading_block_component.dart index ad27c364..528521fe 100644 --- a/lib/src/editor/block_component/heading_block_component/heading_block_component.dart +++ b/lib/src/editor/block_component/heading_block_component/heading_block_component.dart @@ -28,6 +28,7 @@ Node headingNode({ Attributes? attributes, }) { assert(level >= 1 && level <= 6); + return Node( type: HeadingBlockKeys.type, attributes: { @@ -51,6 +52,7 @@ class HeadingBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return HeadingBlockComponentWidget( key: node.key, node: node, @@ -151,6 +153,7 @@ class _HeadingBlockComponentWidgetState widget.textStyleBuilder?.call(level) ?? defaultTextStyle(level), ); + return result; }, placeholderText: placeholderText, @@ -206,6 +209,7 @@ class _HeadingBlockComponentWidgetState TextStyle? defaultTextStyle(int level) { final fontSizes = [32.0, 28.0, 24.0, 18.0, 18.0, 18.0]; final fontSize = fontSizes.elementAtOrNull(level) ?? 18.0; + return TextStyle( fontSize: fontSize, fontWeight: FontWeight.bold, diff --git a/lib/src/editor/block_component/heading_block_component/heading_character_shortcut.dart b/lib/src/editor/block_component/heading_block_component/heading_character_shortcut.dart index f390b051..8086678d 100644 --- a/lib/src/editor/block_component/heading_block_component/heading_character_shortcut.dart +++ b/lib/src/editor/block_component/heading_block_component/heading_character_shortcut.dart @@ -23,6 +23,7 @@ CharacterShortcutEvent formatSignToHeading = CharacterShortcutEvent( }, (text, node, delta) { final numberOfSign = text.split('').length; + return [ headingNode( level: numberOfSign, @@ -61,6 +62,7 @@ CharacterShortcutEvent insertNewLineAfterHeading = CharacterShortcutEvent( Position(path: selection.start.path.next, offset: 0), ); await editorState.apply(transaction); + return true; }, ); diff --git a/lib/src/editor/block_component/image_block_component/base64_image.dart b/lib/src/editor/block_component/image_block_component/base64_image.dart index 6607d264..706562f1 100644 --- a/lib/src/editor/block_component/image_block_component/base64_image.dart +++ b/lib/src/editor/block_component/image_block_component/base64_image.dart @@ -21,5 +21,6 @@ String base64String(Uint8List data) { Future base64StringFromImage(String imagePath) async { final file = File(imagePath); //convert Path to File final imageBytes = await file.readAsBytes(); //convert to bytes + return base64.encode(imageBytes); } diff --git a/lib/src/editor/block_component/image_block_component/image_block_component.dart b/lib/src/editor/block_component/image_block_component/image_block_component.dart index 5726dda1..01c1172f 100644 --- a/lib/src/editor/block_component/image_block_component/image_block_component.dart +++ b/lib/src/editor/block_component/image_block_component/image_block_component.dart @@ -68,6 +68,7 @@ class ImageBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return ImageBlockComponentWidget( key: node.key, node: node, @@ -122,6 +123,7 @@ class ImageBlockComponentWidgetState extends State Node get node => widget.node; final imageKey = GlobalKey(); + RenderBox? get _renderBox => context.findRenderObject() as RenderBox?; late final editorState = Provider.of(context, listen: false); @@ -244,6 +246,7 @@ class ImageBlockComponentWidgetState extends State if (imageBox is RenderBox) { return Offset.zero & imageBox.size; } + return Rect.zero; } @@ -256,6 +259,7 @@ class ImageBlockComponentWidgetState extends State return null; } final size = _renderBox!.size; + return Rect.fromLTWH(-size.width / 2.0, 0, size.width, size.height); } @@ -275,6 +279,7 @@ class ImageBlockComponentWidgetState extends State imageBox.size, ]; } + return [Offset.zero & _renderBox!.size]; } @@ -298,8 +303,10 @@ extension AlignmentExtension on Alignment { switch (name) { case 'left': return Alignment.centerLeft; + case 'right': return Alignment.centerRight; + default: return Alignment.center; } diff --git a/lib/src/editor/block_component/image_block_component/resizable_image.dart b/lib/src/editor/block_component/image_block_component/resizable_image.dart index 5d8e19da..3a520af6 100644 --- a/lib/src/editor/block_component/image_block_component/resizable_image.dart +++ b/lib/src/editor/block_component/image_block_component/resizable_image.dart @@ -91,6 +91,7 @@ class _ResizableImageState extends State { loadingProgress.expectedTotalBytes) { return child; } + return _buildLoading(context); }, errorBuilder: (context, error, stackTrace) => _buildError(context), @@ -101,6 +102,7 @@ class _ResizableImageState extends State { _cacheImage ??= Image.file(File(src)); child = _cacheImage!; } + return Stack( children: [ child, diff --git a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart index 753d6f28..ac20ca70 100644 --- a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart +++ b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart @@ -28,6 +28,7 @@ Node numberedListNode({ 'delta': (delta ?? Delta()).toJson(), NumberedListBlockKeys.number: number, }; + return Node( type: NumberedListBlockKeys.type, attributes: { @@ -56,6 +57,7 @@ class NumberedListBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return NumberedListBlockComponentWidget( key: node.key, node: node, @@ -224,6 +226,7 @@ class _NumberedListIcon extends StatelessWidget { final editorState = context.read(); final text = editorState.editorStyle.textStyleConfiguration.text; final textScaleFactor = editorState.editorStyle.textScaleFactor; + return Container( constraints: const BoxConstraints(minWidth: 26, minHeight: 22) * textScaleFactor, @@ -257,6 +260,7 @@ extension on Node { 2 => indexInSameLevel.roman, _ => '$indexInSameLevel', }; + return '$levelString.'; } } @@ -278,6 +282,7 @@ class _NumberedListIconBuilder { } parent = parent.parent; } + return level; } @@ -300,6 +305,7 @@ class _NumberedListIconBuilder { if (startNumber != null) { return startNumber + level - 1; } + return level; } } @@ -313,6 +319,7 @@ extension on int { result = String.fromCharCode(remainder + 65) + result; number = (number - 1) ~/ 26; } + return result.toLowerCase(); } diff --git a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_character_shortcut.dart b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_character_shortcut.dart index 54734e8a..8978bd9e 100644 --- a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_character_shortcut.dart +++ b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_character_shortcut.dart @@ -50,6 +50,7 @@ CharacterShortcutEvent formatNumberToNumberedList = CharacterShortcutEvent( final match = _numberRegex.firstMatch(text)!; final matchText = match.group(0)!; final number = matchText.substring(0, matchText.length - 1); + return [ node.copyWith( type: NumberedListBlockKeys.type, diff --git a/lib/src/editor/block_component/paragraph_block_component/paragraph_block_component.dart b/lib/src/editor/block_component/paragraph_block_component/paragraph_block_component.dart index c45d8425..7fbcee29 100644 --- a/lib/src/editor/block_component/paragraph_block_component/paragraph_block_component.dart +++ b/lib/src/editor/block_component/paragraph_block_component/paragraph_block_component.dart @@ -46,6 +46,7 @@ class ParagraphBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return ParagraphBlockComponentWidget( node: node, key: node.key, diff --git a/lib/src/editor/block_component/quote_block_component/quote_block_component.dart b/lib/src/editor/block_component/quote_block_component/quote_block_component.dart index 70d590f6..9c0c581b 100644 --- a/lib/src/editor/block_component/quote_block_component/quote_block_component.dart +++ b/lib/src/editor/block_component/quote_block_component/quote_block_component.dart @@ -22,6 +22,7 @@ Node quoteNode({ Iterable? children, }) { attributes ??= {'delta': (delta ?? Delta()).toJson()}; + return Node( type: QuoteBlockKeys.type, attributes: { @@ -43,6 +44,7 @@ class QuoteBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return QuoteBlockComponentWidget( key: node.key, node: node, @@ -194,6 +196,7 @@ class _QuoteIcon extends StatelessWidget { Widget build(BuildContext context) { final textScaleFactor = context.read().editorStyle.textScaleFactor; + return Container( alignment: Alignment.center, constraints: diff --git a/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart b/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart index 9a9439a1..dd667175 100644 --- a/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart +++ b/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart @@ -248,6 +248,7 @@ class _AppFlowyRichTextState extends State widget.cursorWidth, cursorHeight ?? 16.0, ); + return rect; } @@ -256,6 +257,7 @@ class _AppFlowyRichTextState extends State final offset = _renderParagraph?.globalToLocal(start) ?? Offset.zero; final baseOffset = _renderParagraph?.getPositionForOffset(offset).offset ?? -1; + return Position(path: widget.node.path, offset: baseOffset); } @@ -284,6 +286,7 @@ class _AppFlowyRichTextState extends State _renderParagraph?.getWordBoundary(textPosition) ?? TextRange.empty; final start = Position(path: widget.node.path, offset: textRange.start); final end = Position(path: widget.node.path, offset: textRange.end); + return Selection(start: start, end: end); } @@ -294,6 +297,7 @@ class _AppFlowyRichTextState extends State _renderParagraph?.getWordBoundary(textPosition) ?? TextRange.empty; final start = Position(path: widget.node.path, offset: textRange.start); final end = Position(path: widget.node.path, offset: textRange.end); + return Selection(start: start, end: end); } @@ -337,10 +341,12 @@ class _AppFlowyRichTextState extends State height = paragraph?.getFullHeightForCaret(textPosition) ?? height; width = 2; } + return [ Rect.fromLTWH(position.dx, position.dy, width, height), ]; } + return rects; } @@ -360,6 +366,7 @@ class _AppFlowyRichTextState extends State _renderParagraph?.getPositionForOffset(localStart).offset ?? -1; final extentOffset = _renderParagraph?.getPositionForOffset(localEnd).offset ?? -1; + return Selection.single( path: widget.node.path, startOffset: baseOffset, @@ -390,6 +397,7 @@ class _AppFlowyRichTextState extends State if (delta != null && delta.isNotEmpty) { textSpan = textSpan.copyWith(text: ''); } + return RichText( key: placeholderTextKey, textHeightBehavior: TextHeightBehavior( @@ -415,6 +423,7 @@ class _AppFlowyRichTextState extends State textSpan = widget.textSpanDecorator!(textSpan); } textSpan = adjustTextSpan(textSpan); + return RichText( key: textKey, textAlign: widget.textAlign ?? TextAlign.start, @@ -434,6 +443,7 @@ class _AppFlowyRichTextState extends State List _buildRichTextOverlay(BuildContext context) { if (textKey.currentContext == null) return []; + return textSpanOverlayBuilder?.call( context, widget.node, @@ -459,6 +469,7 @@ class _AppFlowyRichTextState extends State textSpan = widget.textSpanDecorator!(textSpan); } textSpan = adjustTextSpan(textSpan); + return ValueListenableBuilder( valueListenable: widget.editorState.selectionNotifier, builder: (_, __, ___) { @@ -488,6 +499,7 @@ class _AppFlowyRichTextState extends State ), ], ); + return RichText( textAlign: widget.textAlign ?? TextAlign.start, textHeightBehavior: TextHeightBehavior( @@ -524,6 +536,7 @@ class _AppFlowyRichTextState extends State fontSize = max(fontSize, style.fontSize!); } } + return true; }); if (height == 0.0 || fontSize == 0.0) { @@ -536,6 +549,7 @@ class _AppFlowyRichTextState extends State ), ); } + return textSpan; } @@ -629,6 +643,7 @@ class _AppFlowyRichTextState extends State ); offset += textInsert.length; } + return TextSpan( children: textSpans, ); @@ -683,6 +698,7 @@ class _AppFlowyRichTextState extends State ); } } + return textSelection; } } @@ -703,18 +719,21 @@ extension AppFlowyRichTextAttributes on Attributes { Color? get color { final textColor = this[AppFlowyRichTextKeys.textColor] as String?; + return textColor?.tryToColor(); } Color? get backgroundColor { final highlightColor = this[AppFlowyRichTextKeys.backgroundColor] as String?; + return highlightColor?.tryToColor(); } Color? get findBackgroundColor { final findBackgroundColor = this[AppFlowyRichTextKeys.findBackgroundColor] as String?; + return findBackgroundColor?.tryToColor(); } @@ -722,6 +741,7 @@ extension AppFlowyRichTextAttributes on Attributes { if (this[AppFlowyRichTextKeys.href] is String) { return this[AppFlowyRichTextKeys.href]; } + return null; } @@ -729,6 +749,7 @@ extension AppFlowyRichTextAttributes on Attributes { if (this[AppFlowyRichTextKeys.fontFamily] is String) { return this[AppFlowyRichTextKeys.fontFamily]; } + return null; } @@ -736,6 +757,7 @@ extension AppFlowyRichTextAttributes on Attributes { if (this[AppFlowyRichTextKeys.fontSize] is double) { return this[AppFlowyRichTextKeys.fontSize]; } + return null; } diff --git a/lib/src/editor/block_component/rich_text/default_selectable_mixin.dart b/lib/src/editor/block_component/rich_text/default_selectable_mixin.dart index 879b984f..fce5d36a 100644 --- a/lib/src/editor/block_component/rich_text/default_selectable_mixin.dart +++ b/lib/src/editor/block_component/rich_text/default_selectable_mixin.dart @@ -19,6 +19,7 @@ mixin DefaultSelectableMixin { return childBox.localToGlobal(Offset.zero, ancestor: parentBox); } } + return Offset.zero; } @@ -33,8 +34,10 @@ mixin DefaultSelectableMixin { if (shiftWithBaseOffset) { return offset & (size - offset as Size); } + return Offset.zero & (size - offset as Size); } + return Rect.zero; } diff --git a/lib/src/editor/block_component/table_block_component/table_action.dart b/lib/src/editor/block_component/table_block_component/table_action.dart index dcbfc327..a332de5f 100644 --- a/lib/src/editor/block_component/table_block_component/table_action.dart +++ b/lib/src/editor/block_component/table_block_component/table_action.dart @@ -194,6 +194,7 @@ void _addRow(Node tableNode, int position, EditorState editorState) async { if (error) { AppFlowyEditorLog.editor.debug('unable to insert row'); + return; } diff --git a/lib/src/editor/block_component/table_block_component/table_block_component.dart b/lib/src/editor/block_component/table_block_component/table_block_component.dart index 34b2d2a8..6ee38e30 100644 --- a/lib/src/editor/block_component/table_block_component/table_block_component.dart +++ b/lib/src/editor/block_component/table_block_component/table_block_component.dart @@ -94,6 +94,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { TableDefaults.rowHeight = tableStyle.rowHeight; TableDefaults.colMinimumWidth = tableStyle.colMinimumWidth; TableDefaults.borderWidth = tableStyle.borderWidth; + return TableBlockComponentWidget( key: node.key, tableNode: TableNode(node: node), @@ -119,6 +120,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { if (node.attributes.isEmpty) { AppFlowyEditorLog.editor .debug('TableBlockComponentBuilder: node is empty'); + return false; } @@ -128,6 +130,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { AppFlowyEditorLog.editor.debug( 'TableBlockComponentBuilder: node has no colsLen or rowsLen', ); + return false; } @@ -139,6 +142,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { if (children.isEmpty) { AppFlowyEditorLog.editor .debug('TableBlockComponentBuilder: children is empty'); + return false; } @@ -146,6 +150,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { AppFlowyEditorLog.editor.debug( 'TableBlockComponentBuilder: children length(${children.length}) is not equal to colsLen * rowsLen($colsLen * $rowsLen)', ); + return false; } @@ -161,6 +166,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { AppFlowyEditorLog.editor.debug( 'TableBlockComponentBuilder: child($i, $j) is empty', ); + return false; } @@ -169,6 +175,7 @@ class TableBlockComponentBuilder extends BlockComponentBuilder { AppFlowyEditorLog.editor.debug( 'TableBlockComponentBuilder: child($i, $j) is not unique', ); + return false; } } @@ -287,6 +294,7 @@ class _TableBlockComponentWidgetState extends State tableBox.size, ]; } + return [Offset.zero & _renderBox.size]; } @@ -323,6 +331,7 @@ class _TableBlockComponentWidgetState extends State bool shiftWithBaseOffset = false, }) { final size = _renderBox.size; + return Rect.fromLTWH(-size.width / 2.0, 0, size.width, size.height); } } diff --git a/lib/src/editor/block_component/table_block_component/table_cell_block_component.dart b/lib/src/editor/block_component/table_block_component/table_cell_block_component.dart index c6602b24..9c6891b8 100644 --- a/lib/src/editor/block_component/table_block_component/table_cell_block_component.dart +++ b/lib/src/editor/block_component/table_block_component/table_cell_block_component.dart @@ -53,6 +53,7 @@ class TableCellBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return TableCelBlockWidget( key: node.key, node: node, diff --git a/lib/src/editor/block_component/table_block_component/table_commands.dart b/lib/src/editor/block_component/table_block_component/table_commands.dart index 388f0382..b70c41da 100644 --- a/lib/src/editor/block_component/table_block_component/table_commands.dart +++ b/lib/src/editor/block_component/table_block_component/table_commands.dart @@ -100,6 +100,7 @@ CommandShortcutEventHandler _enterInTableCellHandler = (editorState) { ); } } + return KeyEventResult.handled; }; @@ -118,8 +119,10 @@ CommandShortcutEventHandler _leftInTableCellHandler = (editorState) { ), ); } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -137,8 +140,10 @@ CommandShortcutEventHandler _rightInTableCellHandler = (editorState) { ), ); } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -156,8 +161,10 @@ CommandShortcutEventHandler _upInTableCellHandler = (editorState) { Selection.single(path: target.path, startOffset: off), ); } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -175,8 +182,10 @@ CommandShortcutEventHandler _downInTableCellHandler = (editorState) { Selection.single(path: target.path, startOffset: off), ); } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -194,8 +203,10 @@ CommandShortcutEventHandler _tabInTableCellHandler = (editorState) { ); } } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -213,8 +224,10 @@ CommandShortcutEventHandler _shiftTabInTableCellHandler = (editorState) { ); } } + return KeyEventResult.handled; } + return KeyEventResult.ignored; }; @@ -243,6 +256,7 @@ Iterable _inTableNodes(EditorState editorState) { return []; } final nodes = editorState.getNodesInSelection(selection); + return nodes.where( (node) => node.parent?.type.contains(TableBlockKeys.type) ?? false, ); diff --git a/lib/src/editor/block_component/table_block_component/table_node.dart b/lib/src/editor/block_component/table_block_component/table_node.dart index 13a766db..45368fc2 100644 --- a/lib/src/editor/block_component/table_block_component/table_node.dart +++ b/lib/src/editor/block_component/table_block_component/table_node.dart @@ -14,6 +14,7 @@ class TableNode { }) : _config = TableConfig.fromJson(node.attributes) { if (node.type != TableBlockKeys.type) { AppFlowyEditorLog.editor.debug('TableNode: node is not a table'); + return; } @@ -28,6 +29,7 @@ class TableNode { AppFlowyEditorLog.editor.debug( 'TableNode: colsLen or rowsLen is not an integer or null', ); + return; } @@ -35,6 +37,7 @@ class TableNode { AppFlowyEditorLog.editor.debug( 'TableNode: the number of children is not equal to the number of cells', ); + return; } @@ -44,6 +47,7 @@ class TableNode { !child.attributes.containsKey(TableCellBlockKeys.colPosition)) { AppFlowyEditorLog.editor .debug('TableNode: cell has no rowPosition or colPosition'); + return; } } @@ -62,6 +66,7 @@ class TableNode { if (cell == null) { AppFlowyEditorLog.editor.debug('TableNode: cell is empty'); _cells.clear(); + return; } diff --git a/lib/src/editor/block_component/table_block_component/util.dart b/lib/src/editor/block_component/table_block_component/util.dart index 3311d9ac..c02b3c4b 100644 --- a/lib/src/editor/block_component/table_block_component/util.dart +++ b/lib/src/editor/block_component/table_block_component/util.dart @@ -24,18 +24,21 @@ extension TableCellNodeDynamicExtension on dynamic { extension TableCellNodeAttributesExtension on Node { double get cellWidth { assert(type == TableCellBlockKeys.type); + return attributes[TableCellBlockKeys.width]?.toDouble() ?? TableDefaults.colWidth; } double get cellHeight { assert(type == TableCellBlockKeys.type); + return attributes[TableCellBlockKeys.height]?.toDouble() ?? TableDefaults.rowHeight; } double get colHeight { assert(type == TableBlockKeys.type); + return attributes[TableBlockKeys.colsHeight]?.toDouble() ?? TableDefaults.rowHeight; } diff --git a/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart b/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart index 395b9e87..584f55c7 100644 --- a/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart +++ b/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart @@ -65,6 +65,7 @@ class TodoListBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return TodoListBlockComponentWidget( key: node.key, node: node, @@ -267,6 +268,7 @@ class _TodoListBlockComponentWidgetState if (!checked) { return null; } + return TextStyle( decoration: TextDecoration.lineThrough, color: Colors.grey.shade400, @@ -287,6 +289,7 @@ class _TodoListIcon extends StatelessWidget { Widget build(BuildContext context) { final textScaleFactor = context.read().editorStyle.textScaleFactor; + return MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( diff --git a/lib/src/editor/block_component/todo_list_block_component/todo_list_command_shortcut.dart b/lib/src/editor/block_component/todo_list_block_component/todo_list_command_shortcut.dart index ffb21f2d..276ca257 100644 --- a/lib/src/editor/block_component/todo_list_block_component/todo_list_command_shortcut.dart +++ b/lib/src/editor/block_component/todo_list_block_component/todo_list_command_shortcut.dart @@ -21,6 +21,7 @@ final CommandShortcutEvent toggleTodoListCommand = CommandShortcutEvent( CommandShortcutEventHandler _toggleTodoListCommandHandler = (editorState) { if (PlatformExtension.isMobile) { assert(false, 'enter key is not supported on mobile platform.'); + return KeyEventResult.ignored; } @@ -45,5 +46,6 @@ CommandShortcutEventHandler _toggleTodoListCommandHandler = (editorState) { } transaction.afterSelection = selection; editorState.apply(transaction); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/command/selection_commands.dart b/lib/src/editor/command/selection_commands.dart index eec819c9..5c4d322b 100644 --- a/lib/src/editor/command/selection_commands.dart +++ b/lib/src/editor/command/selection_commands.dart @@ -28,6 +28,7 @@ extension SelectionTransform on EditorState { final index = delta.prevRunePosition(selection.startIndex); transaction.deleteText(node, index, selection.startIndex - index); await apply(transaction); + return true; } @@ -222,6 +223,7 @@ extension SelectionTransform on EditorState { this.selection = selection.collapse( atStart: direction == SelectionMoveDirection.forward, ); + return; } @@ -253,6 +255,7 @@ extension SelectionTransform on EditorState { reason: SelectionUpdateReason.uiEvent, ); } + return; } // the cursor is at the end of the node @@ -270,6 +273,7 @@ extension SelectionTransform on EditorState { reason: SelectionUpdateReason.uiEvent, ); } + return; } } @@ -293,6 +297,7 @@ extension SelectionTransform on EditorState { throw UnimplementedError(); } break; + case SelectionMoveRange.word: final delta = node.delta; if (delta != null) { @@ -320,6 +325,7 @@ extension SelectionTransform on EditorState { } break; + case SelectionMoveRange.line: if (delta != null) { // move the cursor to the left or right by one line @@ -337,6 +343,7 @@ extension SelectionTransform on EditorState { throw UnimplementedError(); } break; + default: throw UnimplementedError(); } diff --git a/lib/src/editor/command/text_commands.dart b/lib/src/editor/command/text_commands.dart index abc5cc4d..8885c641 100644 --- a/lib/src/editor/command/text_commands.dart +++ b/lib/src/editor/command/text_commands.dart @@ -315,8 +315,10 @@ extension TextTransforms on EditorState { node ??= getNodeAtPath(path!); if (node == null) { assert(false, 'node is null'); + return; } + return apply( transaction..insertText(node, index, text), ); @@ -327,6 +329,7 @@ extension TextTransforms on EditorState { if (selection == null || !selection.isCollapsed) { return; } + return insertText( selection.startIndex, text, @@ -356,6 +359,7 @@ extension TextTransforms on EditorState { final endIndex = node == nodes.last ? selection.endIndex : delta.length; res.add(delta.slice(startIndex, endIndex).toPlainText()); } + return res; } @@ -396,6 +400,7 @@ extension TextTransforms on EditorState { } start += length; } + return null; } diff --git a/lib/src/editor/editor_component/entry/page_block_component.dart b/lib/src/editor/editor_component/entry/page_block_component.dart index 4ff7f7b7..81678e12 100644 --- a/lib/src/editor/editor_component/entry/page_block_component.dart +++ b/lib/src/editor/editor_component/entry/page_block_component.dart @@ -63,6 +63,7 @@ class PageBlockComponent extends BlockComponentStatelessWidget { if (scroller != null) { editorState.updateAutoScroller(scroller); } + return Column( children: [ if (header != null) header!, @@ -72,6 +73,7 @@ class PageBlockComponent extends BlockComponentStatelessWidget { if (wrapper != null) { child = wrapper!(context, node: e, child: child); } + return Container( constraints: BoxConstraints( maxWidth: diff --git a/lib/src/editor/editor_component/service/editor_service.dart b/lib/src/editor/editor_component/service/editor_service.dart index 79ff8ba6..7d4364fd 100644 --- a/lib/src/editor/editor_component/service/editor_service.dart +++ b/lib/src/editor/editor_component/service/editor_service.dart @@ -6,11 +6,13 @@ class EditorService { final selectionServiceKey = GlobalKey( debugLabel: 'appflowy_editor_selection_service', ); + AppFlowySelectionService get selectionService { assert( selectionServiceKey.currentState != null && selectionServiceKey.currentState is AppFlowySelectionService, ); + return selectionServiceKey.currentState! as AppFlowySelectionService; } @@ -18,11 +20,13 @@ class EditorService { final keyboardServiceKey = GlobalKey( debugLabel: 'appflowy_editor_keyboard_service', ); + AppFlowyKeyboardService? get keyboardService { if (keyboardServiceKey.currentState != null && keyboardServiceKey.currentState is AppFlowyKeyboardService) { return keyboardServiceKey.currentState! as AppFlowyKeyboardService; } + return null; } @@ -34,11 +38,13 @@ class EditorService { final scrollServiceKey = GlobalKey( debugLabel: 'appflowy_editor_scroll_service', ); + AppFlowyScrollService? get scrollService { if (scrollServiceKey.currentState != null && scrollServiceKey.currentState is AppFlowyScrollService) { return scrollServiceKey.currentState! as AppFlowyScrollService; } + return null; } } diff --git a/lib/src/editor/editor_component/service/ime/character_shortcut_event_helper.dart b/lib/src/editor/editor_component/service/ime/character_shortcut_event_helper.dart index 5f3d315c..42fa7177 100644 --- a/lib/src/editor/editor_component/service/ime/character_shortcut_event_helper.dart +++ b/lib/src/editor/editor_component/service/ime/character_shortcut_event_helper.dart @@ -28,6 +28,7 @@ Future executeCharacterShortcutEvent( AppFlowyEditorLog.input.debug( 'keyboard service - handled by character shortcut event: $shortcutEvent', ); + return true; } } @@ -36,6 +37,7 @@ Future executeCharacterShortcutEvent( AppFlowyEditorLog.input.debug( 'keyboard service - handled by character shortcut event: $shortcutEvent', ); + return true; } } diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_delete_impl.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_delete_impl.dart index 99ef3d2f..ab1fa1d5 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_delete_impl.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_delete_impl.dart @@ -36,6 +36,7 @@ Future onDelete( ..deleteText(node, start, length) ..afterSelection = afterSelection; await editorState.apply(transaction); + return; } } diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart index 2254784f..9bbfe797 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart @@ -30,6 +30,7 @@ Future onFloatingCursorUpdate( AppFlowyEditorLog.input.debug( 'onFloatingCursorUpdateStart: context is null', ); + return; } @@ -51,6 +52,7 @@ Future onFloatingCursorUpdate( MobileSelectionDragMode.cursor, ); break; + case FloatingCursorDragState.Update: final collapsedCursor = HandleType.collapsed.key; final context = collapsedCursor.currentContext; @@ -58,6 +60,7 @@ Future onFloatingCursorUpdate( AppFlowyEditorLog.input.debug( 'onFloatingCursorUpdateUpdate: context is null', ); + return; } else { AppFlowyEditorLog.input.debug( @@ -80,6 +83,7 @@ Future onFloatingCursorUpdate( MobileSelectionDragMode.cursor, ); break; + case FloatingCursorDragState.End: AppFlowyEditorLog.input.debug( 'onFloatingCursorUpdateEnd: ${point.offset}', diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_insert_impl.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_insert_impl.dart index 23670744..f2c0aa4b 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_insert_impl.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_insert_impl.dart @@ -31,6 +31,7 @@ Future onInsert( if (execution) { editorState.sliceUpcomingAttributes = false; + return; } } diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart index 237547d9..3a4e9d9c 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart @@ -100,12 +100,14 @@ Future _checkIfBacktickPressed( final selection = editorState.selection; if (selection == null || !selection.isCollapsed) { AppFlowyEditorLog.input.debug('selection is null or not collapsed'); + return false; } final node = editorState.getNodesInSelection(selection).firstOrNull; if (node == null) { AppFlowyEditorLog.input.debug('node is null'); + return false; } @@ -113,6 +115,7 @@ Future _checkIfBacktickPressed( final lastCharacter = node.delta?.toPlainText().characters.lastOrNull; if (lastCharacter != '`') { AppFlowyEditorLog.input.debug('last character is not backtick'); + return false; } @@ -127,6 +130,7 @@ Future _checkIfBacktickPressed( if (!shouldApplyFormat) { AppFlowyEditorLog.input.debug('should not apply format'); + return false; } diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_replace_impl.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_replace_impl.dart index 5607399f..1f2a6d88 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_replace_impl.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_replace_impl.dart @@ -79,6 +79,7 @@ extension on TextEditingDeltaReplacement { replacedRange.end, '', ); + return TextEditingDeltaInsertion( oldText: text, textInserted: replacementText, diff --git a/lib/src/editor/editor_component/service/ime/delta_input_service.dart b/lib/src/editor/editor_component/service/ime/delta_input_service.dart index d9f7ed00..f2342398 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_service.dart @@ -36,14 +36,18 @@ class DeltaTextInputService extends TextInputService with DeltaTextInputClient { switch (delta) { case TextEditingDeltaInsertion _: if (!(await onInsert(delta))) willApply = false; + case TextEditingDeltaDeletion _: if (!(await onDelete(delta))) willApply = false; + case TextEditingDeltaReplacement _: if (!(await onReplace(delta))) willApply = false; + case TextEditingDeltaNonTextUpdate _: if (!(await onNonTextUpdate(delta))) willApply = false; } } + return willApply; } @@ -284,6 +288,7 @@ extension on String { if (shiftAmount > length) { return ''; } + return substring(shiftAmount); } } diff --git a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart index b5a21ed7..53f5a2ee 100644 --- a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart @@ -61,6 +61,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { if (!(await onNonTextUpdate(delta))) willApply = false; } } + return willApply; } @@ -109,6 +110,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { AppFlowyEditorLog.editor.debug( 'ignore updateEditingValue event when the floating cursor is visible', ); + return; } @@ -163,6 +165,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { @override Future performAction(TextInputAction action) async { AppFlowyEditorLog.editor.debug('performAction: $action'); + return onPerformAction(action); } @@ -186,9 +189,11 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { case FloatingCursorDragState.Start: _isFloatingCursorVisible = true; break; + case FloatingCursorDragState.Update: _isFloatingCursorVisible = true; break; + case FloatingCursorDragState.End: _isFloatingCursorVisible = false; break; @@ -285,6 +290,7 @@ extension on TextEditingValue { selection.extentOffset > text.length) { return false; } + return true; } @@ -336,6 +342,7 @@ extension on TextEditingDelta { extension TextEditingDeltaInsertionExtension on TextEditingDeltaInsertion { TextEditingDeltaInsertion format() { final startWithSpace = oldText.startsWith(_whitespace); + return TextEditingDeltaInsertion( oldText: startWithSpace ? oldText << _len : oldText, textInserted: textInserted, @@ -405,6 +412,7 @@ extension on String { if (shiftAmount > length) { return ''; } + return substring(shiftAmount); } } diff --git a/lib/src/editor/editor_component/service/ime/text_input_service.dart b/lib/src/editor/editor_component/service/ime/text_input_service.dart index d3f969ac..fc3893da 100644 --- a/lib/src/editor/editor_component/service/ime/text_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/text_input_service.dart @@ -23,6 +23,7 @@ abstract class TextInputService { final ContentInsertionConfiguration? contentInsertionConfiguration; TextRange? get composingTextRange; + bool get attached; void clearComposingTextRange(); diff --git a/lib/src/editor/editor_component/service/keyboard_service_widget.dart b/lib/src/editor/editor_component/service/keyboard_service_widget.dart index fedebef2..ec18cc00 100644 --- a/lib/src/editor/editor_component/service/keyboard_service_widget.dart +++ b/lib/src/editor/editor_component/service/keyboard_service_widget.dart @@ -61,6 +61,7 @@ class KeyboardServiceWidgetState extends State enableIMEShortcuts = true; focusNode.requestFocus(); textInputService.close(); + return true; }, ); @@ -173,6 +174,7 @@ class KeyboardServiceWidgetState extends State if (textInputService.composingTextRange != TextRange.empty) { return KeyEventResult.skipRemainingHandlers; } + return KeyEventResult.ignored; } @@ -184,11 +186,13 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.keyboard.debug( 'keyboard service - handled by command shortcut event: $shortcutEvent', ); + return KeyEventResult.handled; } else if (result == KeyEventResult.skipRemainingHandlers) { AppFlowyEditorLog.keyboard.debug( 'keyboard service - skip by command shortcut event: $shortcutEvent', ); + return KeyEventResult.skipRemainingHandlers; } continue; @@ -296,6 +300,7 @@ class KeyboardServiceWidgetState extends State composing: composingTextRange, ); } + return null; } @@ -371,6 +376,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onInsert - intercepted by interceptor: $interceptor', ); + return false; } } @@ -380,6 +386,7 @@ class KeyboardServiceWidgetState extends State editorState, widget.characterShortcutEvents, ); + return true; }, onDelete: (deletion) async { @@ -392,6 +399,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onDelete - intercepted by interceptor: $interceptor', ); + return false; } } @@ -400,6 +408,7 @@ class KeyboardServiceWidgetState extends State deletion, editorState, ); + return true; }, onReplace: (replacement) async { @@ -413,6 +422,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onReplace - intercepted by interceptor: $interceptor', ); + return false; } } @@ -422,6 +432,7 @@ class KeyboardServiceWidgetState extends State editorState, widget.characterShortcutEvents, ); + return true; }, onNonTextUpdate: (nonTextUpdate) async { @@ -435,6 +446,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onNonTextUpdate - intercepted by interceptor: $interceptor', ); + return false; } } @@ -444,6 +456,7 @@ class KeyboardServiceWidgetState extends State editorState, widget.characterShortcutEvents, ); + return true; }, onPerformAction: (action) async { @@ -456,6 +469,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onPerformAction - intercepted by interceptor: $interceptor', ); + return; } } @@ -475,6 +489,7 @@ class KeyboardServiceWidgetState extends State AppFlowyEditorLog.input.info( 'keyboard service onFloatingCursor - intercepted by interceptor: $interceptor', ); + return; } } diff --git a/lib/src/editor/editor_component/service/renderer/block_component_container.dart b/lib/src/editor/editor_component/service/renderer/block_component_container.dart index 82c20485..dab4421c 100644 --- a/lib/src/editor/editor_component/service/renderer/block_component_container.dart +++ b/lib/src/editor/editor_component/service/renderer/block_component_container.dart @@ -27,6 +27,7 @@ class BlockComponentContainer extends StatelessWidget { builder: (_, __, ___) { AppFlowyEditorLog.editor .debug('node is rebuilding...: type: ${node.type} '); + return CompositedTransformTarget( link: node.layerLink, child: builder(context), diff --git a/lib/src/editor/editor_component/service/renderer/block_component_service.dart b/lib/src/editor/editor_component/service/renderer/block_component_service.dart index e7f2bd99..1173109a 100644 --- a/lib/src/editor/editor_component/service/renderer/block_component_service.dart +++ b/lib/src/editor/editor_component/service/renderer/block_component_service.dart @@ -90,6 +90,7 @@ abstract class BlockComponentRendererService { if (builder is BlockComponentSelectable) { return builder as BlockComponentSelectable; } + return null; } diff --git a/lib/src/editor/editor_component/service/renderer/block_component_widget.dart b/lib/src/editor/editor_component/service/renderer/block_component_widget.dart index 697b9899..2a473d65 100644 --- a/lib/src/editor/editor_component/service/renderer/block_component_widget.dart +++ b/lib/src/editor/editor_component/service/renderer/block_component_widget.dart @@ -107,6 +107,7 @@ mixin NestedBlockComponentStatefulWidgetMixin< ); } } + return configuration.indentPadding(node, direction); } diff --git a/lib/src/editor/editor_component/service/scroll/desktop_scroll_service.dart b/lib/src/editor/editor_component/service/scroll/desktop_scroll_service.dart index c2a2c12b..fdf17418 100644 --- a/lib/src/editor/editor_component/service/scroll/desktop_scroll_service.dart +++ b/lib/src/editor/editor_component/service/scroll/desktop_scroll_service.dart @@ -28,6 +28,7 @@ class _DesktopScrollServiceState extends State @override double? get onePageHeight { final renderBox = context.findRenderObject() as RenderBox?; + return renderBox?.size.height; } @@ -43,8 +44,10 @@ class _DesktopScrollServiceState extends State int? get page { if (onePageHeight != null) { final scrollExtent = maxScrollExtent - minScrollExtent; + return (scrollExtent / onePageHeight!).ceil(); } + return null; } diff --git a/lib/src/editor/editor_component/service/scroll/editor_scroll_controller.dart b/lib/src/editor/editor_component/service/scroll/editor_scroll_controller.dart index 5fbbd210..bb3dc7c0 100644 --- a/lib/src/editor/editor_component/service/scroll/editor_scroll_controller.dart +++ b/lib/src/editor/editor_component/service/scroll/editor_scroll_controller.dart @@ -90,6 +90,7 @@ class EditorScrollController { 'when shrinkWrap is true', ); } + return _itemScrollController; } @@ -102,6 +103,7 @@ class EditorScrollController { 'when shrinkWrap is true', ); } + return _scrollOffsetController; } @@ -115,6 +117,7 @@ class EditorScrollController { 'when shrinkWrap is true', ); } + return _itemPositionsListener; } @@ -128,6 +131,7 @@ class EditorScrollController { 'when shrinkWrap is true', ); } + return _scrollOffsetListener; } @@ -231,6 +235,7 @@ class EditorScrollController { if (positions.isEmpty) { visibleRangeNotifier.value = (-1, -1); + return; } diff --git a/lib/src/editor/editor_component/service/scroll/mobile_scroll_service.dart b/lib/src/editor/editor_component/service/scroll/mobile_scroll_service.dart index 7416005e..a313e9c3 100644 --- a/lib/src/editor/editor_component/service/scroll/mobile_scroll_service.dart +++ b/lib/src/editor/editor_component/service/scroll/mobile_scroll_service.dart @@ -26,6 +26,7 @@ class _MobileScrollServiceState extends State @override double? get onePageHeight { final renderBox = context.findRenderObject() as RenderBox?; + return renderBox?.size.height; } @@ -41,8 +42,10 @@ class _MobileScrollServiceState extends State int? get page { if (onePageHeight != null) { final scrollExtent = maxScrollExtent - minScrollExtent; + return (scrollExtent / onePageHeight!).ceil(); } + return null; } diff --git a/lib/src/editor/editor_component/service/scroll_service.dart b/lib/src/editor/editor_component/service/scroll_service.dart index 30e705c3..0d0711e2 100644 --- a/lib/src/editor/editor_component/service/scroll_service.dart +++ b/lib/src/editor/editor_component/service/scroll_service.dart @@ -41,6 +41,7 @@ abstract class AppFlowyScrollService implements AutoScrollerService { ); void jumpToTop(); + void jumpToBottom(); void goBallistic(double velocity); diff --git a/lib/src/editor/editor_component/service/scroll_service_widget.dart b/lib/src/editor/editor_component/service/scroll_service_widget.dart index 8a896770..e67479cf 100644 --- a/lib/src/editor/editor_component/service/scroll_service_widget.dart +++ b/lib/src/editor/editor_component/service/scroll_service_widget.dart @@ -114,10 +114,12 @@ class _ScrollServiceWidgetState extends State targetRect = selectionRects.first; direction = AxisDirection.up; break; + case 'MobileSelectionDragMode.rightSelectionHandle': targetRect = selectionRects.last; direction = AxisDirection.down; break; + default: targetRect = selectionRects.last; diff --git a/lib/src/editor/editor_component/service/selection/desktop_selection_service.dart b/lib/src/editor/editor_component/service/selection/desktop_selection_service.dart index d652b154..e9abe8d7 100644 --- a/lib/src/editor/editor_component/service/selection/desktop_selection_service.dart +++ b/lib/src/editor/editor_component/service/selection/desktop_selection_service.dart @@ -213,8 +213,10 @@ class _DesktopSelectionServiceWidgetState final selectable = node?.selectable; if (selectable == null) { clearSelection(); + return null; } + return selectable.getPositionInOffset(offset); } @@ -258,6 +260,7 @@ class _DesktopSelectionServiceWidgetState if (selectable == null) { // Clear old start offset _panStartOffset = null; + return clearSelection(); } @@ -292,6 +295,7 @@ class _DesktopSelectionServiceWidgetState final selection = node?.selectable?.getWordBoundaryInOffset(offset); if (selection == null) { clearSelection(); + return; } updateSelection(selection); @@ -310,6 +314,7 @@ class _DesktopSelectionServiceWidgetState final selectable = node?.selectable; if (selectable == null) { clearSelection(); + return; } Selection selection = Selection( @@ -327,6 +332,7 @@ class _DesktopSelectionServiceWidgetState if (selectable == null) { clearSelection(); + return; } @@ -384,6 +390,7 @@ class _DesktopSelectionServiceWidgetState ?.getPositionInOffset(_panStartOffset!); if (_panStartPosition == null) { _resetPanState(); + return; } @@ -620,6 +627,7 @@ class _DesktopSelectionServiceWidgetState (isCloserToStart ? startOffset.dy : endOffset.dy) + editorOffset.dy; final width = blockRect.topRight.dx - startOffset.dx; + return Positioned( top: indicatorTop, left: startOffset.dx + editorOffset.dx, diff --git a/lib/src/editor/editor_component/service/selection/mobile_magnifier.dart b/lib/src/editor/editor_component/service/selection/mobile_magnifier.dart index d66c7bb3..a888511c 100644 --- a/lib/src/editor/editor_component/service/selection/mobile_magnifier.dart +++ b/lib/src/editor/editor_component/service/selection/mobile_magnifier.dart @@ -14,6 +14,7 @@ class MobileMagnifier extends StatelessWidget { Widget build(BuildContext context) { // the magnifier will blink if the center is the same as the offset. final magicOffset = Offset(0, size.height - 22); + return Positioned.fromRect( rect: Rect.fromCenter( center: offset - magicOffset, diff --git a/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart b/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart index 66182045..023fe1f4 100644 --- a/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart +++ b/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart @@ -142,6 +142,7 @@ class _MobileSelectionServiceWidgetState _buildCollapsedHandle(), ], ); + return PlatformExtension.isIOS ? MobileSelectionGestureDetector( onTapUp: _onTapUpIOS, @@ -174,6 +175,7 @@ class _MobileSelectionServiceWidgetState } final renderBox = context.findRenderObject() as RenderBox; final local = renderBox.globalToLocal(offset); + return MobileMagnifier( size: widget.magnifierSize, offset: local, @@ -188,6 +190,7 @@ class _MobileSelectionServiceWidgetState builder: (context, selection, _) { if (selection == null || !selection.isCollapsed) { isCollapsedHandleVisible = false; + return const SizedBox.shrink(); } @@ -196,6 +199,7 @@ class _MobileSelectionServiceWidgetState editorState.selectionUpdateReason != SelectionUpdateReason.uiEvent) { isCollapsedHandleVisible = false; + return const SizedBox.shrink(); } @@ -205,6 +209,7 @@ class _MobileSelectionServiceWidgetState MobileSelectionDragMode.rightSelectionHandle, ].contains(dragMode)) { isCollapsedHandleVisible = false; + return const SizedBox.shrink(); } @@ -219,6 +224,7 @@ class _MobileSelectionServiceWidgetState if (node == null || rect == null) { isCollapsedHandleVisible = false; + return const SizedBox.shrink(); } @@ -227,6 +233,7 @@ class _MobileSelectionServiceWidgetState _clearCollapsedHandleOnAndroid(); final editorStyle = editorState.editorStyle; + return MobileCollapsedHandle( layerLink: node.layerLink, rect: rect, @@ -310,6 +317,7 @@ class _MobileSelectionServiceWidgetState } final editorStyle = editorState.editorStyle; + return MobileSelectionHandle( layerLink: node.layerLink, rect: handleType == HandleType.left ? rects.first : rects.last, @@ -455,15 +463,18 @@ class _MobileSelectionServiceWidgetState end: end, ).normalized; break; + case MobileSelectionDragMode.rightSelectionHandle: newSelection = Selection( start: _panStartSelection!.normalized.start, end: end, ).normalized; break; + case MobileSelectionDragMode.cursor: newSelection = Selection.collapsed(end); break; + case MobileSelectionDragMode.none: return; } @@ -491,8 +502,10 @@ class _MobileSelectionServiceWidgetState final selectable = node?.selectable; if (selectable == null) { clearSelection(); + return null; } + return selectable.getPositionInOffset(offset); } @@ -515,6 +528,7 @@ class _MobileSelectionServiceWidgetState if (currentSelection.value != selection) { clearSelection(); + return; } @@ -619,6 +633,7 @@ class _MobileSelectionServiceWidgetState // if the tap happens on a selection area, don't change the selection if (_isClickOnSelectionArea(offset)) { appFlowyEditorOnTapSelectionArea.add(0); + return; } @@ -655,6 +670,7 @@ class _MobileSelectionServiceWidgetState final selection = node?.selectable?.getWordBoundaryInOffset(offset); if (selection == null) { clearSelection(); + return; } updateSelection(selection); @@ -667,6 +683,7 @@ class _MobileSelectionServiceWidgetState final selectable = node?.selectable; if (selectable == null) { clearSelection(); + return; } Selection selection = Selection( @@ -752,6 +769,7 @@ class _MobileSelectionServiceWidgetState final selection = node?.selectable?.getWordBoundaryInOffset(offset); if (selection == null) { clearSelection(); + return; } @@ -844,6 +862,7 @@ class _MobileSelectionServiceWidgetState if (details.delta.dx.abs() < details.delta.dy.abs() && (_panStartOffset == null || _panStartScrollDy == null)) { _isPanStartHorizontal = false; + return; } // first successful call to onPanUpdate, initialize pan variables @@ -949,6 +968,7 @@ class _MobileSelectionServiceWidgetState return true; } } + return false; } diff --git a/lib/src/editor/editor_component/service/selection/shared.dart b/lib/src/editor/editor_component/service/selection/shared.dart index 88626cfb..e24bada8 100644 --- a/lib/src/editor/editor_component/service/selection/shared.dart +++ b/lib/src/editor/editor_component/service/selection/shared.dart @@ -25,6 +25,7 @@ extension EditorStateSelection on EditorState { } sortedNodes.add(child); } + return sortedNodes; } @@ -52,6 +53,7 @@ extension EditorStateSelection on EditorState { AppFlowyEditorLog.selection.debug( 'findNodeInOffset: $index, rect: $rect, offset: $offset, isMatch: $isMatch', ); + return isMatch; }, compare: (index, rect) => rect.bottom <= offset.dy, @@ -76,6 +78,7 @@ extension EditorStateSelection on EditorState { AppFlowyEditorLog.selection.debug( 'findNodeInOffset: $index, rect: $rect, offset: $offset, isMatch: $isMatch', ); + return isMatch; }, compare: (index, rect) => rect.right <= offset.dx, @@ -98,6 +101,7 @@ extension EditorStateSelection on EditorState { (a, b) { final aRect = _getCachedRect(a, rectCache!); final bRect = _getCachedRect(b, rectCache); + return aRect.bottom != bRect.bottom ? aRect.bottom.compareTo(bRect.bottom) : aRect.left.compareTo(bRect.left); @@ -116,8 +120,10 @@ extension EditorStateSelection on EditorState { final widget = element.widget; if (widget is Opacity && widget.opacity == 0) { isVisible = false; + return false; } + return true; }); if (isVisible) { @@ -142,6 +148,7 @@ extension EditorStateSelection on EditorState { rectCache, ); } + return node; } diff --git a/lib/src/editor/editor_component/service/selection_service.dart b/lib/src/editor/editor_component/service/selection_service.dart index 691f577c..a26f1990 100644 --- a/lib/src/editor/editor_component/service/selection_service.dart +++ b/lib/src/editor/editor_component/service/selection_service.dart @@ -86,6 +86,7 @@ abstract class AppFlowySelectionService { List get selectionRects; void registerGestureInterceptor(SelectionGestureInterceptor interceptor); + void unregisterGestureInterceptor(String key); /// The functions below are only for mobile. @@ -93,10 +94,12 @@ abstract class AppFlowySelectionService { DragStartDetails details, MobileSelectionDragMode mode, ); + Selection? onPanUpdate( DragUpdateDetails details, MobileSelectionDragMode mode, ); + void onPanEnd( DragEndDetails details, MobileSelectionDragMode mode, diff --git a/lib/src/editor/editor_component/service/selection_service_widget.dart b/lib/src/editor/editor_component/service/selection_service_widget.dart index 6e4ad0b1..e706fc4a 100644 --- a/lib/src/editor/editor_component/service/selection_service_widget.dart +++ b/lib/src/editor/editor_component/service/selection_service_widget.dart @@ -37,6 +37,7 @@ class _SelectionServiceWidgetState extends State final forwardKey = GlobalKey( debugLabel: 'forward_to_platform_selection_service', ); + AppFlowySelectionService get forward => forwardKey.currentState as AppFlowySelectionService; @@ -55,6 +56,7 @@ class _SelectionServiceWidgetState extends State } final editorState = context.read(); + return MobileSelectionServiceWidget( key: forwardKey, cursorColor: widget.cursorColor, diff --git a/lib/src/editor/editor_component/service/shortcuts/character/format_double_character/format_double_characters.dart b/lib/src/editor/editor_component/service/shortcuts/character/format_double_character/format_double_characters.dart index 09ff371f..a08e46fc 100644 --- a/lib/src/editor/editor_component/service/shortcuts/character/format_double_character/format_double_characters.dart +++ b/lib/src/editor/editor_component/service/shortcuts/character/format_double_character/format_double_characters.dart @@ -89,6 +89,7 @@ bool handleFormatByWrappingWithDoubleCharacter({ case DoubleCharacterFormatStyle.bold: style = 'bold'; break; + case DoubleCharacterFormatStyle.strikethrough: style = 'strikethrough'; break; @@ -117,5 +118,6 @@ bool handleFormatByWrappingWithDoubleCharacter({ ), ); editorState.apply(format); + return true; } diff --git a/lib/src/editor/editor_component/service/shortcuts/character/format_single_character/format_single_character.dart b/lib/src/editor/editor_component/service/shortcuts/character/format_single_character/format_single_character.dart index 97fefc5e..5c118f2e 100644 --- a/lib/src/editor/editor_component/service/shortcuts/character/format_single_character/format_single_character.dart +++ b/lib/src/editor/editor_component/service/shortcuts/character/format_single_character/format_single_character.dart @@ -34,6 +34,7 @@ class CheckSingleFormatFormatResult { }) { if (character.length != 1) { AppFlowyEditorLog.input.debug('character length is not 1'); + return (false, null); } @@ -41,6 +42,7 @@ class CheckSingleFormatFormatResult { // We should return false to let the IME handle it. if (!selection.isCollapsed || selection.end.offset < 2) { AppFlowyEditorLog.input.debug('selection is not valid'); + return (false, null); } @@ -58,6 +60,7 @@ class CheckSingleFormatFormatResult { if (op.attributes?[AppFlowyRichTextKeys.code] == true) { return true; } + return false; }); int startIndex = 0; @@ -69,6 +72,7 @@ class CheckSingleFormatFormatResult { if (index <= lastInlineCodeIndex) { return sum + op.length; } + return sum; }); } @@ -146,6 +150,7 @@ bool handleFormatByWrappingWithSingleCharacter({ if (!shouldApply || formatResult == null) { AppFlowyEditorLog.input.debug('format single character failed'); + return false; } @@ -179,9 +184,11 @@ bool handleFormatByWrappingWithSingleCharacter({ case FormatStyleByWrappingWithSingleChar.code: style = 'code'; break; + case FormatStyleByWrappingWithSingleChar.italic: style = 'italic'; break; + case FormatStyleByWrappingWithSingleChar.strikethrough: style = 'strikethrough'; break; @@ -207,5 +214,6 @@ bool handleFormatByWrappingWithSingleCharacter({ ), ); editorState.apply(format); + return true; } diff --git a/lib/src/editor/editor_component/service/shortcuts/character/slash_command.dart b/lib/src/editor/editor_component/service/shortcuts/character/slash_command.dart index 57fb3207..962719c2 100644 --- a/lib/src/editor/editor_component/service/shortcuts/character/slash_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/character/slash_command.dart @@ -79,6 +79,7 @@ Future _showSlashMenu( final afterSelection = editorState.selection; if (afterSelection == null || !afterSelection.isCollapsed) { assert(false, 'the selection should be collapsed'); + return true; } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/arrow_down_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/arrow_down_command.dart index 7bcad389..224c885c 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/arrow_down_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/arrow_down_command.dart @@ -126,5 +126,6 @@ CommandShortcutEventHandler _moveCursorDownSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/arrow_left_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/arrow_left_command.dart index be67f541..0d42ccd8 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/arrow_left_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/arrow_left_command.dart @@ -36,6 +36,7 @@ CommandShortcutEventHandler _arrowLeftCommandHandler = (editorState) { } else { editorState.moveCursorForward(SelectionMoveRange.character); } + return KeyEventResult.handled; }; @@ -59,6 +60,7 @@ CommandShortcutEventHandler _moveCursorToBeginCommandHandler = (editorState) { } else { editorState.moveCursorForward(SelectionMoveRange.line); } + return KeyEventResult.handled; }; @@ -119,6 +121,7 @@ CommandShortcutEventHandler _moveCursorToLeftWordCommandHandler = } editorState.moveCursorForward(SelectionMoveRange.word); } + return KeyEventResult.handled; }; @@ -154,6 +157,7 @@ CommandShortcutEventHandler _moveCursorLeftWordSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; @@ -184,6 +188,7 @@ CommandShortcutEventHandler _moveCursorLeftSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; @@ -217,13 +222,16 @@ CommandShortcutEventHandler _moveCursorBeginSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; bool isRTL(EditorState editorState) { if (editorState.selection != null) { final node = editorState.getNodeAtPath(editorState.selection!.end.path); + return node?.selectable?.textDirection() == TextDirection.rtl; } + return false; } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/arrow_right_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/arrow_right_command.dart index 3d66ea3f..833cb77f 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/arrow_right_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/arrow_right_command.dart @@ -36,6 +36,7 @@ CommandShortcutEventHandler _arrowRightCommandHandler = (editorState) { } else { editorState.moveCursorBackward(SelectionMoveRange.character); } + return KeyEventResult.handled; }; @@ -59,6 +60,7 @@ CommandShortcutEventHandler _moveCursorToEndCommandHandler = (editorState) { } else { editorState.moveCursorBackward(SelectionMoveRange.line); } + return KeyEventResult.handled; }; @@ -123,6 +125,7 @@ CommandShortcutEventHandler _moveCursorToRightWordCommandHandler = } editorState.moveCursorBackward(SelectionMoveRange.word); } + return KeyEventResult.handled; }; @@ -158,6 +161,7 @@ CommandShortcutEventHandler _moveCursorRightWordSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; @@ -188,6 +192,7 @@ CommandShortcutEventHandler _moveCursorRightSelectCommandHandler = selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; @@ -220,5 +225,6 @@ CommandShortcutEventHandler _moveCursorEndSelectCommandHandler = (editorState) { selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/arrow_up_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/arrow_up_command.dart index 21d1eb06..87b339b8 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/arrow_up_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/arrow_up_command.dart @@ -65,6 +65,7 @@ CommandShortcutEventHandler _moveCursorTopSelectCommandHandler = (editorState) { selection.copyWith(end: position), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; @@ -122,5 +123,6 @@ CommandShortcutEventHandler _moveCursorUpSelectCommandHandler = (editorState) { selection.copyWith(end: end), reason: SelectionUpdateReason.uiEvent, ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/backspace_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/backspace_command.dart index 97aee49d..2a0b2949 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/backspace_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/backspace_command.dart @@ -62,6 +62,7 @@ CommandShortcutEventHandler _backspaceInCollapsedSelection = (editorState) { ), ); editorState.apply(transaction); + return KeyEventResult.handled; } @@ -141,6 +142,7 @@ CommandShortcutEventHandler _backspaceInCollapsedSelection = (editorState) { } editorState.apply(transaction); + return KeyEventResult.handled; }; @@ -151,6 +153,7 @@ CommandShortcutEventHandler _backspaceInNotCollapsedSelection = (editorState) { return KeyEventResult.ignored; } editorState.deleteSelection(selection); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/copy_paste_extension.dart b/lib/src/editor/editor_component/service/shortcuts/command/copy_paste_extension.dart index f7fe07dd..fedf4ed0 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/copy_paste_extension.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/copy_paste_extension.dart @@ -66,6 +66,7 @@ extension EditorCopyPaste on EditorState { if (startWithNonDeltaBlock) { transaction.insertNodes(node.path.next, nodes); await apply(transaction); + return; } @@ -133,6 +134,7 @@ extension EditorCopyPaste on EditorState { // fetch selection again.selection = editorState.selection; assert(this.selection?.isCollapsed == true); + return this.selection; } @@ -148,6 +150,7 @@ extension EditorCopyPaste on EditorState { ...calculatePath([0], nodes.last.children.toList()), ]; } + return path; } @@ -155,6 +158,7 @@ extension EditorCopyPaste on EditorState { if (nodes.last.children.isNotEmpty) { return calculateLength(nodes.last.children.toList()); } + return nodes.last.delta?.length ?? 0; } } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/cut_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/cut_command.dart index 0296ac68..00915310 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/cut_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/cut_command.dart @@ -21,5 +21,6 @@ CommandShortcutEventHandler _cutCommandHandler = (editorState) { } // plain text. handleCut(editorState); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/delete_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/delete_command.dart index 6d421b34..0f48f284 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/delete_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/delete_command.dart @@ -72,6 +72,7 @@ CommandShortcutEventHandler _deleteInCollapsedSelection = (editorState) { next, ); editorState.apply(transaction); + return KeyEventResult.handled; } } else { @@ -83,6 +84,7 @@ CommandShortcutEventHandler _deleteInCollapsedSelection = (editorState) { nextIndex - position.offset, ); editorState.apply(transaction); + return KeyEventResult.handled; } } @@ -97,6 +99,7 @@ CommandShortcutEventHandler _deleteInNotCollapsedSelection = (editorState) { return KeyEventResult.ignored; } editorState.deleteSelection(selection); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/end_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/end_command.dart index f959753a..ddf03b26 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/end_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/end_command.dart @@ -25,5 +25,6 @@ CommandShortcutEventHandler _endCommandHandler = (editorState) { scrollService.maxScrollExtent, duration: const Duration(milliseconds: 150), ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/escape_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/escape_command.dart index 73a5bd80..8e509c2c 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/escape_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/escape_command.dart @@ -17,5 +17,6 @@ final CommandShortcutEvent exitEditingCommand = CommandShortcutEvent( CommandShortcutEventHandler _exitEditingCommandHandler = (editorState) { editorState.selection = null; editorState.service.keyboardService?.closeKeyboard(); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/home_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/home_command.dart index 1822de2d..97478a45 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/home_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/home_command.dart @@ -25,5 +25,6 @@ CommandShortcutEventHandler _homeCommandHandler = (editorState) { scrollService.minScrollExtent, duration: const Duration(milliseconds: 150), ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/page_down_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/page_down_command.dart index 644334ea..947d2bc4 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/page_down_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/page_down_command.dart @@ -31,5 +31,6 @@ CommandShortcutEventHandler _pageUpCommandHandler = (editorState) { dy + scrollHeight, duration: const Duration(milliseconds: 150), ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/page_up_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/page_up_command.dart index 0505e683..49d81069 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/page_up_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/page_up_command.dart @@ -18,6 +18,7 @@ final CommandShortcutEvent pageUpCommand = CommandShortcutEvent( CommandShortcutEventHandler _pageUpCommandHandler = (editorState) { if (PlatformExtension.isMobile) { assert(false, 'pageUpCommand is not supported on mobile platform.'); + return KeyEventResult.ignored; } final scrollService = editorState.service.scrollService; @@ -34,5 +35,6 @@ CommandShortcutEventHandler _pageUpCommandHandler = (editorState) { dy - scrollHeight, duration: const Duration(milliseconds: 150), ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/paste_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/paste_command.dart index 1687ec2b..8fb8be63 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/paste_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/paste_command.dart @@ -104,6 +104,7 @@ extension on EditorState { } else { await pasteMultiLineNodes(nodes.toList()); } + return true; } @@ -161,6 +162,7 @@ extension on EditorState { } else { delta.insert(paragraph, attributes: selectionAttributes); } + return delta; }) .map((paragraph) => paragraphNode(delta: paragraph)) @@ -196,6 +198,7 @@ extension on EditorState { AppFlowyRichTextKeys.href: isPhone ? 'tel:$plainText' : plainText, }); await apply(transaction); + return true; } } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/remove_line_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/remove_line_command.dart index 0c296040..b0469f3e 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/remove_line_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/remove_line_command.dart @@ -36,5 +36,6 @@ CommandShortcutEventHandler _deleteLeftSentenceCommandHandler = (editorState) { selection.endIndex, ); editorState.apply(transaction); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/select_all_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/select_all_command.dart index 25c64eba..e9396b40 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/select_all_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/select_all_command.dart @@ -30,5 +30,6 @@ CommandShortcutEventHandler _selectAllCommandHandler = (editorState) { Selection(start: start, end: end), reason: SelectionUpdateReason.selectAll, ); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/service/shortcuts/command/show_link_menu_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/show_link_menu_command.dart index 64e50efd..c837662e 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/show_link_menu_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/show_link_menu_command.dart @@ -19,6 +19,7 @@ KeyEventResult _showLinkMenu( ) { if (PlatformExtension.isMobile) { assert(false, 'showLinkMenuCommand is not supported on mobile platform.'); + return KeyEventResult.ignored; } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/toggle_colors_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/toggle_colors_command.dart index 5d7b4e9f..e71659c6 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/toggle_colors_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/toggle_colors_command.dart @@ -55,6 +55,7 @@ KeyEventResult _toggleHighlight( }) { if (PlatformExtension.isMobile) { assert(false, 'toggle highlight is not supported on mobile platform.'); + return KeyEventResult.ignored; } diff --git a/lib/src/editor/editor_component/service/shortcuts/command/undo_redo_command.dart b/lib/src/editor/editor_component/service/shortcuts/command/undo_redo_command.dart index 1e2b069e..1f0936a4 100644 --- a/lib/src/editor/editor_component/service/shortcuts/command/undo_redo_command.dart +++ b/lib/src/editor/editor_component/service/shortcuts/command/undo_redo_command.dart @@ -17,6 +17,7 @@ final CommandShortcutEvent undoCommand = CommandShortcutEvent( CommandShortcutEventHandler _undoCommandHandler = (editorState) { editorState.undoManager.undo(); + return KeyEventResult.handled; }; @@ -36,5 +37,6 @@ final CommandShortcutEvent redoCommand = CommandShortcutEvent( CommandShortcutEventHandler _redoCommandHandler = (editorState) { editorState.undoManager.redo(); + return KeyEventResult.handled; }; diff --git a/lib/src/editor/editor_component/style/default_text_span_decorator_for_attribute.dart b/lib/src/editor/editor_component/style/default_text_span_decorator_for_attribute.dart index ffafab3b..5431dd98 100644 --- a/lib/src/editor/editor_component/style/default_text_span_decorator_for_attribute.dart +++ b/lib/src/editor/editor_component/style/default_text_span_decorator_for_attribute.dart @@ -39,6 +39,7 @@ TextSpan defaultTextSpanDecoratorForAttribute( HardwareKeyboard.instance.isMetaPressed) { tapCount = 0; editorLaunchUrl(href); + return; } timer = Timer(const Duration(milliseconds: 200), () { @@ -65,5 +66,6 @@ TextSpan defaultTextSpanDecoratorForAttribute( mouseCursor: SystemMouseCursors.click, ); } + return before; } diff --git a/lib/src/editor/editor_component/style/mobile_text_span_decorator_for_attribute.dart b/lib/src/editor/editor_component/style/mobile_text_span_decorator_for_attribute.dart index 1321f2c1..21a342db 100644 --- a/lib/src/editor/editor_component/style/mobile_text_span_decorator_for_attribute.dart +++ b/lib/src/editor/editor_component/style/mobile_text_span_decorator_for_attribute.dart @@ -31,6 +31,7 @@ TextSpan mobileTextSpanDecoratorForAttribute( // Implement single tap logic safeLaunchUrl(hrefAddress); timer!.cancel(); + return; } }; @@ -69,6 +70,7 @@ TextSpan mobileTextSpanDecoratorForAttribute( ); }); }; + return TextSpan( style: before.style, text: text.text, @@ -124,6 +126,7 @@ class _LinkEditFormState extends State { if (value == null || value.isEmpty) { return AppFlowyEditorL10n.current.linkTextHint; } + return null; }, decoration: InputDecoration( @@ -145,6 +148,7 @@ class _LinkEditFormState extends State { if (value == null || value.isEmpty) { return AppFlowyEditorL10n.current.linkAddressHint; } + return null; }, decoration: InputDecoration( diff --git a/lib/src/editor/find_replace_menu/find_menu_service.dart b/lib/src/editor/find_replace_menu/find_menu_service.dart index 25ad3449..d599a36f 100644 --- a/lib/src/editor/find_replace_menu/find_menu_service.dart +++ b/lib/src/editor/find_replace_menu/find_menu_service.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; abstract class FindReplaceService { void show(); + void dismiss(); } @@ -125,6 +126,7 @@ class FindReplaceMenu implements FindReplaceService { if (_selectionUpdateByInner) { _selectionUpdateByInner = false; + return; } diff --git a/lib/src/editor/find_replace_menu/find_replace_widget.dart b/lib/src/editor/find_replace_menu/find_replace_widget.dart index 4740af17..f5a92d32 100644 --- a/lib/src/editor/find_replace_menu/find_replace_widget.dart +++ b/lib/src/editor/find_replace_menu/find_replace_widget.dart @@ -201,6 +201,7 @@ class _FindMenuState extends State { // the selectedIndex from searchService is 0-based final selectedIndex = widget.searchService.selectedIndex + 1; final matches = widget.searchService.matchWrappers.value; + return Row( children: [ // expand/collapse button @@ -348,8 +349,10 @@ class _FindMenuState extends State { switch (error) { case 'Regex': message = AppFlowyEditorLocalizations.current.regexError; + case 'Empty': message = AppFlowyEditorLocalizations.current.emptySearchBoxHint; + default: message = widget.localizations?.noResult ?? AppFlowyEditorLocalizations.current.noFindResult; diff --git a/lib/src/editor/find_replace_menu/search_algorithm.dart b/lib/src/editor/find_replace_menu/search_algorithm.dart index 78c675ab..8b67d971 100644 --- a/lib/src/editor/find_replace_menu/search_algorithm.dart +++ b/lib/src/editor/find_replace_menu/search_algorithm.dart @@ -34,6 +34,7 @@ final class BoyerMooreMatch implements Match { if (group != 0) { throw RangeError.value(group); } + return pattern; } diff --git a/lib/src/editor/find_replace_menu/search_service_v2.dart b/lib/src/editor/find_replace_menu/search_service_v2.dart index 993040bd..869ed428 100644 --- a/lib/src/editor/find_replace_menu/search_service_v2.dart +++ b/lib/src/editor/find_replace_menu/search_service_v2.dart @@ -18,14 +18,18 @@ class SearchServiceV2 { SearchAlgorithm searchAlgorithm = BoyerMoore(); String queriedPattern = ''; bool _caseSensitive = false; + bool get caseSensitive => _caseSensitive; + set caseSensitive(bool value) { _caseSensitive = value; findAndHighlight(queriedPattern); } int _selectedIndex = 0; + int get selectedIndex => _selectedIndex; + set selectedIndex(int index) { _prevSelectedIndex = _selectedIndex; _selectedIndex = matchedPositions.value.isEmpty @@ -97,6 +101,7 @@ class SearchServiceV2 { _getMatchedPositions(pattern: pattern, nodes: node.children), ); } + return result; } diff --git a/lib/src/editor/find_replace_menu/search_service_v3.dart b/lib/src/editor/find_replace_menu/search_service_v3.dart index c51e8c16..822b221b 100644 --- a/lib/src/editor/find_replace_menu/search_service_v3.dart +++ b/lib/src/editor/find_replace_menu/search_service_v3.dart @@ -21,21 +21,27 @@ class SearchServiceV3 { Pattern queriedPattern = RegExp(''); bool _regex = false; + bool get regex => _regex; + set regex(bool value) { _regex = value; findAndHighlight(targetString); } bool _caseSensitive = false; + bool get caseSensitive => _caseSensitive; + set caseSensitive(bool value) { _caseSensitive = value; findAndHighlight(targetString); } int _selectedIndex = 0; + int get selectedIndex => _selectedIndex; + set selectedIndex(int index) { _selectedIndex = matchWrappers.value.isEmpty ? -1 @@ -79,6 +85,7 @@ class SearchServiceV3 { pattern = _getPattern(target); } on FormatException { matchWrappers.value.clear(); + return 'Regex'; } @@ -147,6 +154,7 @@ class SearchServiceV3 { _getMatchWrappers(pattern: pattern, nodes: node.children), ); } + return result; } diff --git a/lib/src/editor/selection_menu/selection_menu_item_widget.dart b/lib/src/editor/selection_menu/selection_menu_item_widget.dart index 7c79440f..444bdd47 100644 --- a/lib/src/editor/selection_menu/selection_menu_item_widget.dart +++ b/lib/src/editor/selection_menu/selection_menu_item_widget.dart @@ -33,6 +33,7 @@ class _SelectionMenuItemWidgetState extends State { Widget build(BuildContext context) { final style = widget.selectionMenuStyle; final isSelected = widget.isSelected || _onHover; + return Container( padding: const EdgeInsets.fromLTRB(8.0, 5.0, 8.0, 5.0), child: SizedBox( diff --git a/lib/src/editor/selection_menu/selection_menu_service.dart b/lib/src/editor/selection_menu/selection_menu_service.dart index fb284662..73974b16 100644 --- a/lib/src/editor/selection_menu/selection_menu_service.dart +++ b/lib/src/editor/selection_menu/selection_menu_service.dart @@ -77,6 +77,7 @@ class SelectionMenu extends SelectionMenuService { _show(); completer.complete(); }); + return completer.future; } @@ -176,6 +177,7 @@ class SelectionMenu extends SelectionMenuService { if (_selectionUpdateByInner) { _selectionUpdateByInner = false; + return; } @@ -190,14 +192,17 @@ class SelectionMenu extends SelectionMenuService { left = offset.dx; top = offset.dy; break; + case Alignment.bottomLeft: left = offset.dx; bottom = offset.dy; break; + case Alignment.topRight: right = offset.dx; top = offset.dy; break; + case Alignment.bottomRight: right = offset.dx; bottom = offset.dy; diff --git a/lib/src/editor/selection_menu/selection_menu_widget.dart b/lib/src/editor/selection_menu/selection_menu_widget.dart index 9fc6050e..a25946e5 100644 --- a/lib/src/editor/selection_menu/selection_menu_widget.dart +++ b/lib/src/editor/selection_menu/selection_menu_widget.dart @@ -52,6 +52,7 @@ class SelectionMenuItem { /// /// The keywords are used to quickly retrieve items. final List keywords; + List get allKeywords => keywords + [name.toLowerCase()]; late final SelectionMenuItemHandler handler; @@ -307,7 +308,9 @@ class _SelectionMenuWidgetState extends State { int _searchCounter = 0; String _keyword = ''; + String get keyword => _keyword; + set keyword(String newKeyword) { _keyword = newKeyword; @@ -321,6 +324,7 @@ class _SelectionMenuWidgetState extends State { if (value) { maxKeywordLength = max(maxKeywordLength, keyword.length); } + return value; }), ) @@ -431,6 +435,7 @@ class _SelectionMenuWidgetState extends State { ), ); } + return ConstrainedBox( constraints: const BoxConstraints( maxHeight: 300, @@ -480,6 +485,7 @@ class _SelectionMenuWidgetState extends State { ); itemWidgets = []; } + return Row( crossAxisAlignment: CrossAxisAlignment.start, children: columns, @@ -528,10 +534,12 @@ class _SelectionMenuWidgetState extends State { if (0 <= _selectedIndex && _selectedIndex < _showingItems.length) { _showingItems[_selectedIndex] .handler(widget.editorState, widget.menuService, context); + return KeyEventResult.handled; } } else if (event.logicalKey == LogicalKeyboardKey.escape) { widget.onExit(); + return KeyEventResult.handled; } else if (event.logicalKey == LogicalKeyboardKey.backspace) { if (_searchCounter > 0) { @@ -543,12 +551,14 @@ class _SelectionMenuWidgetState extends State { keyword = keyword.substring(0, keyword.length - 1); } _deleteLastCharacters(); + return KeyEventResult.handled; } else if (event.character != null && !arrowKeys.contains(event.logicalKey) && event.logicalKey != LogicalKeyboardKey.tab) { keyword += event.character!; _insertText(event.character!); + return KeyEventResult.handled; } @@ -602,8 +612,10 @@ class _SelectionMenuWidgetState extends State { _selectedIndex = newSelectedIndex.clamp(0, _showingItems.length - 1); _scrollToSelectedIndex(); }); + return KeyEventResult.handled; } + return KeyEventResult.ignored; } diff --git a/lib/src/editor/toolbar/desktop/floating_toolbar.dart b/lib/src/editor/toolbar/desktop/floating_toolbar.dart index c63975c7..9ff2b081 100644 --- a/lib/src/editor/toolbar/desktop/floating_toolbar.dart +++ b/lib/src/editor/toolbar/desktop/floating_toolbar.dart @@ -213,6 +213,7 @@ class _FloatingToolbarState extends State if (nodes.isEmpty || nodes.every((node) { final delta = node.delta; + return delta == null || delta.isEmpty; })) { return; @@ -233,6 +234,7 @@ class _FloatingToolbarState extends State _toolbarContainer = OverlayEntry( builder: (context) { final child = _buildToolbar(context); + return widget.toolbarBuilder ?.call(context, child, _clear, isMetricsChanged) ?? Positioned( @@ -269,6 +271,7 @@ class _FloatingToolbarState extends State placeHolderBuilder: widget.placeHolderBuilder, ); } + return _toolbarWidget!; } diff --git a/lib/src/editor/toolbar/desktop/floating_toolbar_widget.dart b/lib/src/editor/toolbar/desktop/floating_toolbar_widget.dart index 8353b39b..d9606346 100644 --- a/lib/src/editor/toolbar/desktop/floating_toolbar_widget.dart +++ b/lib/src/editor/toolbar/desktop/floating_toolbar_widget.dart @@ -55,6 +55,7 @@ class FloatingToolbarWidget extends StatefulWidget { class _FloatingToolbarWidgetState extends State { EditorState get editorState => widget.editorState; + PropertyValueNotifier get selectionNotifier => editorState.selectionNotifier; @@ -86,6 +87,7 @@ class _FloatingToolbarWidgetState extends State { if (activeItems.isEmpty) { return const SizedBox.shrink(); } + return Material( borderRadius: BorderRadius.circular(8.0), color: widget.backgroundColor, diff --git a/lib/src/editor/toolbar/desktop/items/color/color_picker.dart b/lib/src/editor/toolbar/desktop/items/color/color_picker.dart index bab90039..0f3d5ea9 100644 --- a/lib/src/editor/toolbar/desktop/items/color/color_picker.dart +++ b/lib/src/editor/toolbar/desktop/items/color/color_picker.dart @@ -133,11 +133,13 @@ class _ColorPickerState extends State { if (colorHex == null) return null; final opacityHex = colorHex.substring(2, 4); final opacity = int.parse(opacityHex, radix: 16) / 2.55; + return opacity.toStringAsFixed(0); } String? _extractColorHex(String? colorHex) { if (colorHex == null) return null; + return colorHex.substring(4); } } @@ -180,6 +182,7 @@ class ResetColorButton extends StatelessWidget { if (states.contains(WidgetState.hovered)) { return Theme.of(context).hoverColor; } + return Colors.transparent; }, ), @@ -295,6 +298,7 @@ class _CustomColorItemState extends State { colorHex = _fixColorHex(colorHex); opacity = _fixOpacity(opacity); final opacityHex = (int.parse(opacity) * 2.55).round().toRadixString(16); + return '0x$opacityHex$colorHex'; } @@ -305,6 +309,7 @@ class _CustomColorItemState extends State { if (int.tryParse(colorHex, radix: 16) == null) { colorHex = 'FFFFFF'; } + return colorHex; } diff --git a/lib/src/editor/toolbar/desktop/items/color/highlight_color_toolbar_item.dart b/lib/src/editor/toolbar/desktop/items/color/highlight_color_toolbar_item.dart index 7c30bbc3..90b3ce04 100644 --- a/lib/src/editor/toolbar/desktop/items/color/highlight_color_toolbar_item.dart +++ b/lib/src/editor/toolbar/desktop/items/color/highlight_color_toolbar_item.dart @@ -19,6 +19,7 @@ ToolbarItem buildHighlightColorItem({List? colorOptions}) { return delta.everyAttributes((attributes) { highlightColorHex = attributes[AppFlowyRichTextKeys.backgroundColor]; + return highlightColorHex != null; }); }); @@ -40,6 +41,7 @@ ToolbarItem buildHighlightColorItem({List? colorOptions}) { }, ); } + return true; }); showColorMenu( diff --git a/lib/src/editor/toolbar/desktop/items/color/text_color_toolbar_item.dart b/lib/src/editor/toolbar/desktop/items/color/text_color_toolbar_item.dart index 9f099325..cfaa69db 100644 --- a/lib/src/editor/toolbar/desktop/items/color/text_color_toolbar_item.dart +++ b/lib/src/editor/toolbar/desktop/items/color/text_color_toolbar_item.dart @@ -20,6 +20,7 @@ ToolbarItem buildTextColorItem({ return delta.everyAttributes((attr) { textColorHex = attr[AppFlowyRichTextKeys.textColor]; + return (textColorHex != null); }); }); @@ -43,6 +44,7 @@ ToolbarItem buildTextColorItem({ }, ); } + return true; }, ); diff --git a/lib/src/editor/toolbar/desktop/items/heading_toolbar_items.dart b/lib/src/editor/toolbar/desktop/items/heading_toolbar_items.dart index 28f54e15..ec116479 100644 --- a/lib/src/editor/toolbar/desktop/items/heading_toolbar_items.dart +++ b/lib/src/editor/toolbar/desktop/items/heading_toolbar_items.dart @@ -68,6 +68,7 @@ class _HeadingToolbarItem extends ToolbarItem { } else if (level == 3) { return AppFlowyEditorL10n.current.heading3; } + return ''; } } diff --git a/lib/src/editor/toolbar/desktop/items/link/link_menu.dart b/lib/src/editor/toolbar/desktop/items/link/link_menu.dart index c3a99b02..1d1522e0 100644 --- a/lib/src/editor/toolbar/desktop/items/link/link_menu.dart +++ b/lib/src/editor/toolbar/desktop/items/link/link_menu.dart @@ -119,6 +119,7 @@ class _LinkMenuState extends State { if (value == null || value.isEmpty || !isUri(value)) { return AppFlowyEditorL10n.current.incorrectLink; } + return null; }, ), diff --git a/lib/src/editor/toolbar/desktop/items/utils/overlay_util.dart b/lib/src/editor/toolbar/desktop/items/utils/overlay_util.dart index 4890bc8d..6056e523 100644 --- a/lib/src/editor/toolbar/desktop/items/utils/overlay_util.dart +++ b/lib/src/editor/toolbar/desktop/items/utils/overlay_util.dart @@ -8,6 +8,7 @@ ButtonStyle buildOverlayButtonStyle(BuildContext context) { if (states.contains(WidgetState.hovered)) { return Theme.of(context).hoverColor; } + return Colors.transparent; }, ), diff --git a/lib/src/editor/toolbar/desktop/items/utils/tooltip_util.dart b/lib/src/editor/toolbar/desktop/items/utils/tooltip_util.dart index 45c49dab..84cb1925 100644 --- a/lib/src/editor/toolbar/desktop/items/utils/tooltip_util.dart +++ b/lib/src/editor/toolbar/desktop/items/utils/tooltip_util.dart @@ -15,6 +15,7 @@ String shortcutTooltips( } else if (PlatformExtension.isLinux && linuxString != null) { return '\n$linuxString'; } + return ''; } @@ -22,26 +23,37 @@ String getTooltipText(String id) { switch (id) { case 'underline': return '${AppFlowyEditorL10n.current.underline}${shortcutTooltips('⌘ + U', 'CTRL + U', 'CTRL + U')}'; + case 'bold': return '${AppFlowyEditorL10n.current.bold}${shortcutTooltips('⌘ + B', 'CTRL + B', 'CTRL + B')}'; + case 'italic': return '${AppFlowyEditorL10n.current.italic}${shortcutTooltips('⌘ + I', 'CTRL + I', 'CTRL + I')}'; + case 'strikethrough': return '${AppFlowyEditorL10n.current.strikethrough}${shortcutTooltips('⌘ + SHIFT + S', 'CTRL + SHIFT + S', 'CTRL + SHIFT + S')}'; + case 'code': return '${AppFlowyEditorL10n.current.embedCode}${shortcutTooltips('⌘ + E', 'CTRL + E', 'CTRL + E')}'; + case 'align_left': return AppFlowyEditorL10n.current.textAlignLeft; + case 'align_center': return AppFlowyEditorL10n.current.textAlignCenter; + case 'align_right': return AppFlowyEditorL10n.current.textAlignRight; + case 'text_direction_auto': return AppFlowyEditorL10n.current.auto; + case 'text_direction_ltr': return AppFlowyEditorL10n.current.ltr; + case 'text_direction_rtl': return AppFlowyEditorL10n.current.rtl; + default: return ''; } diff --git a/lib/src/editor/toolbar/mobile/mobile_floating_toolbar/mobile_floating_toolbar.dart b/lib/src/editor/toolbar/mobile/mobile_floating_toolbar/mobile_floating_toolbar.dart index e2bc94cd..2b88b5ed 100644 --- a/lib/src/editor/toolbar/mobile/mobile_floating_toolbar/mobile_floating_toolbar.dart +++ b/lib/src/editor/toolbar/mobile/mobile_floating_toolbar/mobile_floating_toolbar.dart @@ -110,6 +110,7 @@ class _MobileFloatingToolbarState extends State _onScrollEnd!.call(); _onScrollEnd = null; } + return false; }, child: widget.child, diff --git a/lib/src/editor/toolbar/mobile/mobile_toolbar.dart b/lib/src/editor/toolbar/mobile/mobile_toolbar.dart index e73232fe..f2b0c37d 100644 --- a/lib/src/editor/toolbar/mobile/mobile_toolbar.dart +++ b/lib/src/editor/toolbar/mobile/mobile_toolbar.dart @@ -52,6 +52,7 @@ class MobileToolbar extends StatelessWidget { if (selection == null) { return const SizedBox.shrink(); } + return RepaintBoundary( child: MobileToolbarTheme( backgroundColor: backgroundColor, @@ -280,6 +281,7 @@ class _ToolbarItemListView extends StatelessWidget { if (icon == null) { return const SizedBox.shrink(); } + return IconButton( icon: icon, onPressed: () { diff --git a/lib/src/editor/toolbar/mobile/mobile_toolbar_v2.dart b/lib/src/editor/toolbar/mobile/mobile_toolbar_v2.dart index 61bce534..010a40ec 100644 --- a/lib/src/editor/toolbar/mobile/mobile_toolbar_v2.dart +++ b/lib/src/editor/toolbar/mobile/mobile_toolbar_v2.dart @@ -123,6 +123,7 @@ class _MobileToolbarV2State extends State { true) { return const SizedBox.shrink(); } + return RepaintBoundary( child: MobileToolbarTheme( backgroundColor: widget.backgroundColor, @@ -402,6 +403,7 @@ class _MobileToolbarState extends State<_MobileToolbar> ); } } + return SizedBox( height: keyboardHeight, child: (showingMenu && selectedMenuIndex != null) @@ -415,6 +417,7 @@ class _MobileToolbarState extends State<_MobileToolbar> widget.editorState, this, ); + return menu ?? const SizedBox.shrink(); }, ) @@ -466,6 +469,7 @@ class _ToolbarItemListView extends StatelessWidget { if (icon == null) { return const SizedBox.shrink(); } + return IconButton( icon: icon, onPressed: () { diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/blocks_mobile_toolbar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/blocks_mobile_toolbar_item.dart index 5c818235..7c050f79 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/blocks_mobile_toolbar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/blocks_mobile_toolbar_item.dart @@ -11,6 +11,7 @@ final blocksMobileToolbarItem = MobileToolbarItem.withMenu( if (selection == null) { return const SizedBox.shrink(); } + return _BlocksMenu(editorState, selection); }, ); diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/color/background_color_options_widgets.dart b/lib/src/editor/toolbar/mobile/toolbar_items/color/background_color_options_widgets.dart index d483ea47..8f877f1a 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/color/background_color_options_widgets.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/color/background_color_options_widgets.dart @@ -65,6 +65,7 @@ class _BackgroundColorOptionsWidgetsState e.colorHex, ); }); + return ColorButton( isBackgroundColor: true, colorOption: e, diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/color/text_and_background_color_tool_bar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/color/text_and_background_color_tool_bar_item.dart index e7e35555..c9a78092 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/color/text_and_background_color_tool_bar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/color/text_and_background_color_tool_bar_item.dart @@ -15,6 +15,7 @@ MobileToolbarItem buildTextAndBackgroundColorMobileToolbarItem({ if (selection == null) { return const SizedBox.shrink(); } + return _TextAndBackgroundColorMenu( editorState, selection, diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/color/text_color_options_widgets.dart b/lib/src/editor/toolbar/mobile/toolbar_items/color/text_color_options_widgets.dart index 69987a2f..bbeae65b 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/color/text_color_options_widgets.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/color/text_color_options_widgets.dart @@ -63,6 +63,7 @@ class _TextColorOptionsWidgetsState extends State { attributes[AppFlowyRichTextKeys.textColor] == e.colorHex, ); }); + return ColorButton( colorOption: e, onPressed: () { diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/clear_color_button.dart b/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/clear_color_button.dart index 80e76da8..09381ffe 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/clear_color_button.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/clear_color_button.dart @@ -41,6 +41,7 @@ class ClearColorButton extends StatelessWidget { class _DiagonalLinePainter extends CustomPainter { _DiagonalLinePainter(this.diagonalLineColor); final Color diagonalLineColor; + @override void paint(Canvas canvas, Size size) { final paint = Paint() diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/color_button.dart b/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/color_button.dart index dab24a99..b02cd982 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/color_button.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/color/utils/color_button.dart @@ -18,6 +18,7 @@ class ColorButton extends StatelessWidget { @override Widget build(BuildContext context) { final style = MobileToolbarTheme.of(context); + return InkWell( onTap: onPressed, child: Container( diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/heading_mobile_toolbar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/heading_mobile_toolbar_item.dart index c858a9bd..3e91370b 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/heading_mobile_toolbar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/heading_mobile_toolbar_item.dart @@ -11,6 +11,7 @@ final headingMobileToolbarItem = MobileToolbarItem.withMenu( if (selection == null) { return const SizedBox.shrink(); } + return _HeadingMenu( selection, editorState, diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/link_mobile_toolbar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/link_mobile_toolbar_item.dart index 8ef148fb..0657d0bc 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/link_mobile_toolbar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/link_mobile_toolbar_item.dart @@ -72,6 +72,7 @@ class _MobileLinkMenuState extends State { Widget build(BuildContext context) { final style = MobileToolbarTheme.of(context); const double spacing = 8; + return Material( // TextField widget needs to be wrapped in a Material widget to provide a visual appearance color: style.backgroundColor, diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/list_mobile_toolbar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/list_mobile_toolbar_item.dart index 237ab104..f144e957 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/list_mobile_toolbar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/list_mobile_toolbar_item.dart @@ -11,6 +11,7 @@ final listMobileToolbarItem = MobileToolbarItem.withMenu( if (selection == null) { return const SizedBox.shrink(); } + return _ListMenu(editorState, selection); }, ); @@ -41,6 +42,7 @@ class _ListMenuState extends State<_ListMenu> { name: 'numbered_list', ), ]; + @override Widget build(BuildContext context) { final btnList = lists.map((currentList) { diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item.dart b/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item.dart index 80605864..539918d4 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item.dart @@ -11,6 +11,7 @@ final textDecorationMobileToolbarItem = MobileToolbarItem.withMenu( if (selection == null) { return const SizedBox.shrink(); } + return _TextDecorationMenu(editorState, selection); }, ); @@ -51,6 +52,7 @@ class _TextDecorationMenuState extends State<_TextDecorationMenu> { name: AppFlowyRichTextKeys.strikethrough, ), ]; + @override Widget build(BuildContext context) { final style = MobileToolbarTheme.of(context); diff --git a/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item_v2.dart b/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item_v2.dart index 0ecc3c13..d3d860d7 100644 --- a/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item_v2.dart +++ b/lib/src/editor/toolbar/mobile/toolbar_items/text_decoration_mobile_toolbar_item_v2.dart @@ -11,6 +11,7 @@ final textDecorationMobileToolbarItemV2 = MobileToolbarItem.withMenu( if (selection == null) { return const SizedBox.shrink(); } + return _TextDecorationMenu(editorState, selection); }, ); diff --git a/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_item_menu_btn.dart b/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_item_menu_btn.dart index d99842a5..c8f44f12 100644 --- a/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_item_menu_btn.dart +++ b/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_item_menu_btn.dart @@ -18,6 +18,7 @@ class MobileToolbarItemMenuBtn extends StatelessWidget { @override Widget build(BuildContext context) { final style = MobileToolbarTheme.of(context); + return OutlinedButton( onPressed: onPressed, style: ButtonStyle( @@ -32,6 +33,7 @@ class MobileToolbarItemMenuBtn extends StatelessWidget { width: style.buttonSelectedBorderWidth, ); } + return BorderSide(color: style.itemOutlineColor); }, ), diff --git a/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_menu_grid_delegate.dart b/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_menu_grid_delegate.dart index f3e70e23..bc05971e 100644 --- a/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_menu_grid_delegate.dart +++ b/lib/src/editor/toolbar/mobile/utils/mobile_toolbar_menu_grid_delegate.dart @@ -48,6 +48,7 @@ class SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight assert(mainAxisSpacing >= 0.0); assert(crossAxisSpacing >= 0.0); assert(height > 0.0); + return true; } @@ -58,6 +59,7 @@ class SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1); final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount; final double childMainAxisExtent = height; + return SliverGridRegularTileLayout( crossAxisCount: crossAxisCount, mainAxisStride: childMainAxisExtent + mainAxisSpacing, diff --git a/lib/src/editor/util/delta_util.dart b/lib/src/editor/util/delta_util.dart index e3923838..783fb903 100644 --- a/lib/src/editor/util/delta_util.dart +++ b/lib/src/editor/util/delta_util.dart @@ -4,6 +4,7 @@ extension AttributesDelta on Delta { bool everyAttributes(bool Function(Attributes element) test) => whereType().every((element) { final attributes = element.attributes; + return attributes != null && test(attributes); }); } diff --git a/lib/src/editor/util/editor_state_selectable_extension.dart b/lib/src/editor/util/editor_state_selectable_extension.dart index 88123034..e71c66a0 100644 --- a/lib/src/editor/util/editor_state_selectable_extension.dart +++ b/lib/src/editor/util/editor_state_selectable_extension.dart @@ -9,6 +9,7 @@ extension EditorStateSelectable on EditorState { return (nodes[i], selectable); } } + return null; } @@ -19,6 +20,7 @@ extension EditorStateSelectable on EditorState { if (node != null) { return (node, renderer.blockComponentSelectable(node.type)!); } + return null; } } diff --git a/lib/src/editor/util/file_picker/file_picker_impl.dart b/lib/src/editor/util/file_picker/file_picker_impl.dart index b1b640ff..e36d3020 100644 --- a/lib/src/editor/util/file_picker/file_picker_impl.dart +++ b/lib/src/editor/util/file_picker/file_picker_impl.dart @@ -30,6 +30,7 @@ class FilePicker implements FilePickerService { withReadStream: withReadStream, lockParentWindow: lockParentWindow, ); + return FilePickerResult(result?.files ?? []); } diff --git a/lib/src/editor/util/link_util.dart b/lib/src/editor/util/link_util.dart index 5810d0d9..6ea1431a 100644 --- a/lib/src/editor/util/link_util.dart +++ b/lib/src/editor/util/link_util.dart @@ -2,6 +2,7 @@ import 'package:string_validator/string_validator.dart'; bool isUri(String text) { final lowerText = text.toLowerCase(); + return isURL(text) || isCustomUrL(text) || lowerText.startsWith('mailto:') || diff --git a/lib/src/editor/util/platform_extension.dart b/lib/src/editor/util/platform_extension.dart index 80544369..ff46ffcd 100644 --- a/lib/src/editor/util/platform_extension.dart +++ b/lib/src/editor/util/platform_extension.dart @@ -29,6 +29,7 @@ extension PlatformExtension on Platform { if (!kIsWeb) { return false; } + return _webPlatform.contains('mac') == true; } @@ -37,6 +38,7 @@ extension PlatformExtension on Platform { if (!kIsWeb) { return false; } + return _webPlatform.contains('windows') == true; } @@ -45,6 +47,7 @@ extension PlatformExtension on Platform { if (!kIsWeb) { return false; } + return _webPlatform.contains('linux') == true; } diff --git a/lib/src/editor/util/property_notifier.dart b/lib/src/editor/util/property_notifier.dart index d03d8519..7a440a35 100644 --- a/lib/src/editor/util/property_notifier.dart +++ b/lib/src/editor/util/property_notifier.dart @@ -20,6 +20,7 @@ class PropertyValueNotifier extends ChangeNotifier @override T get value => _value; T _value; + set value(T newValue) { _value = newValue; notifyListeners(); diff --git a/lib/src/editor/util/text_direction.dart b/lib/src/editor/util/text_direction.dart index b9759899..22b7e0ff 100644 --- a/lib/src/editor/util/text_direction.dart +++ b/lib/src/editor/util/text_direction.dart @@ -16,5 +16,6 @@ TextDirection? determineTextDirection(String text) { return TextDirection.ltr; } } + return null; } diff --git a/lib/src/editor_state.dart b/lib/src/editor_state.dart index 0a174bc2..9b075d09 100644 --- a/lib/src/editor_state.dart +++ b/lib/src/editor_state.dart @@ -260,6 +260,7 @@ class EditorState { Transaction get transaction { final transaction = Transaction(document: document); transaction.beforeSelection = selection; + return transaction; } @@ -275,6 +276,7 @@ class EditorState { /// The rules to apply to the document. List get documentRules => _documentRules; List _documentRules = []; + set documentRules(List value) { _documentRules = value; @@ -318,6 +320,7 @@ class EditorState { if (renderObject != null && renderObject is RenderBox) { return renderObject; } + return null; } @@ -363,6 +366,7 @@ class EditorState { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { completer.complete(); }); + return completer.future; } diff --git a/lib/src/extensions/alignment_extension.dart b/lib/src/extensions/alignment_extension.dart index cfbffe8c..45e3f9b6 100644 --- a/lib/src/extensions/alignment_extension.dart +++ b/lib/src/extensions/alignment_extension.dart @@ -5,6 +5,7 @@ extension AppFlowyTextAlign on Alignment { switch (this) { case Alignment.center: return TextAlign.center; + case Alignment.centerRight: return TextAlign.right; case Alignment.centerLeft: diff --git a/lib/src/extensions/attributes_extension.dart b/lib/src/extensions/attributes_extension.dart index 790e25f3..9cecb164 100644 --- a/lib/src/extensions/attributes_extension.dart +++ b/lib/src/extensions/attributes_extension.dart @@ -8,6 +8,7 @@ extension NodeAttributesExtensions on Attributes { this[BuiltInAttributeKey.heading] is String) { return this[BuiltInAttributeKey.heading]; } + return null; } @@ -20,6 +21,7 @@ extension NodeAttributesExtensions on Attributes { this[BuiltInAttributeKey.number] is num) { return this[BuiltInAttributeKey.number]; } + return null; } @@ -28,6 +30,7 @@ extension NodeAttributesExtensions on Attributes { this[BuiltInAttributeKey.checkbox] is bool) { return this[BuiltInAttributeKey.checkbox]; } + return false; } } diff --git a/lib/src/extensions/node_extensions.dart b/lib/src/extensions/node_extensions.dart index 3a7c118a..35c12100 100644 --- a/lib/src/extensions/node_extensions.dart +++ b/lib/src/extensions/node_extensions.dart @@ -19,6 +19,7 @@ extension NodeExtensions on Node { level++; parent = parent.parent; } + return level; } @@ -33,8 +34,10 @@ extension NodeExtensions on Node { Rect get rect { if (renderBox != null) { final boxOffset = renderBox!.localToGlobal(Offset.zero); + return boxOffset & renderBox!.size; } + return Rect.zero; } @@ -90,8 +93,10 @@ extension NodeExtensions on Node { if (test(parent)) { return parent; } + return parent.previousNodeWhere(test); } + return null; } @@ -109,6 +114,7 @@ extension NodeExtensions on Node { return child; } } + return null; } @@ -131,8 +137,10 @@ extension NodeExtensions on Node { if (test(next)) { return next; } + return next.findDownward(test); } + return null; } @@ -164,6 +172,7 @@ extension NodeExtensions on Node { } parent = parent.parent; } + return false; } @@ -172,6 +181,7 @@ extension NodeExtensions on Node { return this; } final parent = this.parent; + return parent?.findParent(test); } } @@ -198,7 +208,7 @@ extension NodesExtensions on List { } selection = selection.normalized; - final nodes = this.normalized; + final nodes = normalized; if (nodes.length == 1) { return nodes.first.allSatisfyInSelection(selection, test); diff --git a/lib/src/extensions/object_extensions.dart b/lib/src/extensions/object_extensions.dart index b1b6e535..6f091460 100644 --- a/lib/src/extensions/object_extensions.dart +++ b/lib/src/extensions/object_extensions.dart @@ -3,6 +3,7 @@ extension FlowyObjectExtensions on Object { if (this is T) { return this as T; } + return null; } } diff --git a/lib/src/extensions/position_extension.dart b/lib/src/extensions/position_extension.dart index 450a30bf..d98bf406 100644 --- a/lib/src/extensions/position_extension.dart +++ b/lib/src/extensions/position_extension.dart @@ -24,6 +24,7 @@ extension PositionExtension on Position { if (previousEnd != null) { return previousEnd; } + return null; } else if (!forward) { final end = node.selectable?.end(); @@ -45,6 +46,7 @@ extension PositionExtension on Position { } return Position(path: path, offset: offset); + case SelectionRange.word: final delta = node.delta; if (delta != null) { @@ -86,6 +88,7 @@ extension PositionExtension on Position { if (editorSelection.isBackward) { return current.bottom > next.bottom ? current : next; } + return current.top <= next.top ? current : next; }); @@ -104,6 +107,7 @@ extension PositionExtension on Position { ?.configuration; if (nodeConfig == null) { assert(nodeConfig != null, 'Block Configuration should not be null'); + return this; } @@ -212,6 +216,7 @@ extension PositionExtension on Position { selectable.start().offset, selectable.end().offset, ); + return Position(path: neighbourPath, offset: offset); } } diff --git a/lib/src/extensions/text_style_extension.dart b/lib/src/extensions/text_style_extension.dart index 68982b83..8fc685d9 100644 --- a/lib/src/extensions/text_style_extension.dart +++ b/lib/src/extensions/text_style_extension.dart @@ -22,12 +22,14 @@ extension TextSpanExtensions on TextSpan { if (other == null) { return this; } + return copyWith( style: style?.combine(other), children: children?.map((child) { if (child is TextSpan) { return child.updateTextStyle(other); } + return child; }).toList(growable: false), ); diff --git a/lib/src/extensions/theme_extension.dart b/lib/src/extensions/theme_extension.dart index 9b8f01aa..68310666 100644 --- a/lib/src/extensions/theme_extension.dart +++ b/lib/src/extensions/theme_extension.dart @@ -5,6 +5,7 @@ extension ThemeExtension on ThemeData { if (extensions.containsKey(T)) { return extensions[T] as T; } + return null; } } diff --git a/lib/src/extensions/url_launcher_extension.dart b/lib/src/extensions/url_launcher_extension.dart index 059a4a4c..0207f8bb 100644 --- a/lib/src/extensions/url_launcher_extension.dart +++ b/lib/src/extensions/url_launcher_extension.dart @@ -10,6 +10,7 @@ Future safeLaunchUrl(String? href) async { if (await canLaunchUrlString(newHref)) { await launchUrlString(newHref); } + return Future.value(true); } diff --git a/lib/src/flutter/overlay.dart b/lib/src/flutter/overlay.dart index 01cff5c7..05516a74 100644 --- a/lib/src/flutter/overlay.dart +++ b/lib/src/flutter/overlay.dart @@ -88,6 +88,7 @@ class OverlayEntry extends ChangeNotifier { /// set. bool get opaque => _opaque; bool _opaque; + set opaque(bool value) { if (_opaque == value) return; _opaque = value; @@ -110,6 +111,7 @@ class OverlayEntry extends ChangeNotifier { /// from subsequent routes will be handled properly when they complete. bool get maintainState => _maintainState; bool _maintainState; + set maintainState(bool value) { if (_maintainState == value) return; _maintainState = value; @@ -122,6 +124,7 @@ class OverlayEntry extends ChangeNotifier { /// The [OverlayEntry] notifies its listeners when this value changes. bool get mounted => _mounted; bool _mounted = false; + void _updateMounted(bool value) { if (value == _mounted) { return; @@ -320,8 +323,10 @@ class Overlay extends StatefulWidget { throw FlutterError.fromParts(information); } + return true; }()); + return result; } @@ -349,6 +354,7 @@ class OverlayState extends State with TickerProviderStateMixin { assert(above == null || below == null); if (below != null) return _entries.indexOf(below); if (above != null) return _entries.indexOf(above) + 1; + return _entries.length; } @@ -429,6 +435,7 @@ class OverlayState extends State with TickerProviderStateMixin { (newEntries?.contains(below) ?? true)), 'The provided entry used for `below` must be present in the Overlay${newEntries != null ? ' and in the `newEntriesList`' : ''}.', ); + return true; } @@ -513,8 +520,10 @@ class OverlayState extends State with TickerProviderStateMixin { } if (candidate.opaque) break; } + return true; }()); + return result; } @@ -553,6 +562,7 @@ class OverlayState extends State with TickerProviderStateMixin { ); } } + return _Theatre( skipCount: children.length - onstageCount, clipBehavior: widget.clipBehavior, @@ -664,6 +674,7 @@ class _RenderTheatre extends RenderBox TextDirection get textDirection => _textDirection; TextDirection _textDirection; + set textDirection(TextDirection value) { if (_textDirection == value) return; _textDirection = value; @@ -672,6 +683,7 @@ class _RenderTheatre extends RenderBox int get skipCount => _skipCount; int _skipCount; + set skipCount(int value) { if (_skipCount != value) { _skipCount = value; @@ -684,6 +696,7 @@ class _RenderTheatre extends RenderBox /// Defaults to [Clip.hardEdge], and must not be null. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; + set clipBehavior(Clip value) { if (value != _clipBehavior) { _clipBehavior = value; @@ -703,6 +716,7 @@ class _RenderTheatre extends RenderBox child = childParentData.nextSibling; assert(child != null); } + return child; } @@ -763,6 +777,7 @@ class _RenderTheatre extends RenderBox } child = childParentData.nextSibling; } + return result; } @@ -772,6 +787,7 @@ class _RenderTheatre extends RenderBox @override Size computeDryLayout(BoxConstraints constraints) { assert(constraints.biggest.isFinite); + return constraints.biggest; } @@ -826,12 +842,14 @@ class _RenderTheatre extends RenderBox position: position, hitTest: (BoxHitTestResult result, Offset transformed) { assert(transformed == position - childParentData.offset); + return child!.hitTest(result, position: transformed); }, ); if (isHit) return true; child = childParentData.previousSibling; } + return false; } diff --git a/lib/src/flutter/scrollable_helpers.dart b/lib/src/flutter/scrollable_helpers.dart index b30b1678..bda704ad 100644 --- a/lib/src/flutter/scrollable_helpers.dart +++ b/lib/src/flutter/scrollable_helpers.dart @@ -113,6 +113,7 @@ class ScrollableDetails { addIfNonNull('scroll controller: ', controller); addIfNonNull('scroll physics: ', physics); addIfNonNull('decorationClipBehavior: ', decorationClipBehavior); + return '${describeIdentity(this)}(${description.join(", ")})'; } @@ -128,6 +129,7 @@ class ScrollableDetails { if (other.runtimeType != runtimeType) { return false; } + return other is ScrollableDetails && other.direction == direction && other.controller == controller && @@ -208,6 +210,7 @@ class EdgeDraggingAutoScroller { } AxisDirection get _axisDirection => scrollable.axisDirection; + Axis get _scrollDirection => axisDirectionToAxis(_axisDirection); /// Starts the auto scroll if the [dragTarget] is close to the edge. @@ -338,12 +341,14 @@ class EdgeDraggingAutoScroller { if (newOffset == null) { // Drag should not trigger scroll. _scrolling = false; + return; } double delta = newOffset - currentPixels; if (delta.abs() < _minimumAutoScrollDelta) { if (delta.abs() <= precisionErrorTolerance) { _scrolling = false; + return; } final double direction = delta.sign; @@ -356,6 +361,7 @@ class EdgeDraggingAutoScroller { delta = newOffset - currentPixels; if (delta.abs() <= precisionErrorTolerance) { _scrolling = false; + return; } } @@ -387,11 +393,13 @@ class EdgeDraggingAutoScroller { ); if (_previousScrollDelta == null) { _previousScrollDelta = clampedDelta; + return clampedDelta; } final double smoothed = lerpDouble(_previousScrollDelta!, clampedDelta, 0.35)!; _previousScrollDelta = smoothed; + return smoothed; } } @@ -500,6 +508,7 @@ class ScrollAction extends ContextAction { } final ScrollController? primaryScrollController = PrimaryScrollController.maybeOf(context); + return (primaryScrollController != null) && primaryScrollController.hasClients; } @@ -525,6 +534,7 @@ class ScrollAction extends ContextAction { ScrollIncrementDetails(type: type, metrics: state.position), ); } + return switch (type) { ScrollIncrementType.line => 50.0, ScrollIncrementType.page => 0.8 * state.position.viewportDimension, @@ -541,8 +551,10 @@ class ScrollAction extends ContextAction { axisDirectionToAxis(state.axisDirection)) { final double increment = _calculateScrollIncrement(state, type: intent.type); + return intent.direction == state.axisDirection ? increment : -increment; } + return 0.0; } @@ -573,6 +585,7 @@ class ScrollAction extends ContextAction { ), ]); } + return true; }()); diff --git a/lib/src/flutter/scrollable_positioned_list/src/positioned_list.dart b/lib/src/flutter/scrollable_positioned_list/src/positioned_list.dart index 35908ec1..808ca9e8 100644 --- a/lib/src/flutter/scrollable_positioned_list/src/positioned_list.dart +++ b/lib/src/flutter/scrollable_positioned_list/src/positioned_list.dart @@ -326,6 +326,7 @@ class _PositionedListState extends State { final elements = registeredElements.value; if (elements == null) { updateScheduled = false; + return; } final positions = []; diff --git a/lib/src/flutter/scrollable_positioned_list/src/scroll_view.dart b/lib/src/flutter/scrollable_positioned_list/src/scroll_view.dart index 644bbe6e..a6b7ef27 100644 --- a/lib/src/flutter/scrollable_positioned_list/src/scroll_view.dart +++ b/lib/src/flutter/scrollable_positioned_list/src/scroll_view.dart @@ -61,6 +61,7 @@ class UnboundedCustomScrollView extends CustomScrollView { anchor: anchor, ); } + return UnboundedViewport( axisDirection: axisDirection, offset: offset, diff --git a/lib/src/flutter/scrollable_positioned_list/src/scrollable_positioned_list.dart b/lib/src/flutter/scrollable_positioned_list/src/scrollable_positioned_list.dart index 0afb213f..0c49f44b 100644 --- a/lib/src/flutter/scrollable_positioned_list/src/scrollable_positioned_list.dart +++ b/lib/src/flutter/scrollable_positioned_list/src/scrollable_positioned_list.dart @@ -246,6 +246,7 @@ class ItemScrollController { assert(_scrollableListState != null); assert(opacityAnimationWeights.length == 3); assert(duration > Duration.zero); + return _scrollableListState!._scrollTo( index: index, alignment: alignment, @@ -491,6 +492,7 @@ class _ScrollablePositionedListState extends State ], ), ); + return child; }, ); @@ -652,6 +654,7 @@ class _ScrollablePositionedListState extends State Animatable _opacityAnimation(List opacityAnimationWeights) { const startOpacity = 0.0; const endOpacity = 1.0; + return TweenSequence(>[ TweenSequenceItem( tween: ConstantTween(startOpacity), diff --git a/lib/src/flutter/scrollable_positioned_list/src/viewport.dart b/lib/src/flutter/scrollable_positioned_list/src/viewport.dart index b0c99c43..83411a9c 100644 --- a/lib/src/flutter/scrollable_positioned_list/src/viewport.dart +++ b/lib/src/flutter/scrollable_positioned_list/src/viewport.dart @@ -102,6 +102,7 @@ class UnboundedRenderViewport extends RenderViewport { case Axis.vertical: offset.applyViewportDimension(size.height); break; + case Axis.horizontal: offset.applyViewportDimension(size.width); break; @@ -122,6 +123,7 @@ class UnboundedRenderViewport extends RenderViewport { semanticBounds.right, semanticBounds.bottom + _calculatedCacheExtent!, ); + default: return Rect.fromLTRB( semanticBounds.left - _calculatedCacheExtent!, @@ -140,6 +142,7 @@ class UnboundedRenderViewport extends RenderViewport { _maxScrollExtent = 0.0; _hasVisualOverflow = false; offset.applyContentDimensions(0.0, 0.0); + return; } assert(center!.parent == this); @@ -151,6 +154,7 @@ class UnboundedRenderViewport extends RenderViewport { mainAxisExtent = size.height; crossAxisExtent = size.width; break; + case Axis.horizontal: mainAxisExtent = size.width; crossAxisExtent = size.height; @@ -203,6 +207,7 @@ class UnboundedRenderViewport extends RenderViewport { ' so complicated that it cannot be resolved in any reasonable number of' ' layout passes.'); } + return true; }()); } @@ -234,6 +239,7 @@ class UnboundedRenderViewport extends RenderViewport { case CacheExtentStyle.pixel: _calculatedCacheExtent = cacheExtent; break; + case CacheExtentStyle.viewport: _calculatedCacheExtent = mainAxisExtent * cacheExtent!; break; @@ -298,6 +304,7 @@ class UnboundedRenderViewport extends RenderViewport { case GrowthDirection.forward: _maxScrollExtent += childLayoutGeometry.scrollExtent; break; + case GrowthDirection.reverse: _minScrollExtent -= childLayoutGeometry.scrollExtent; break; diff --git a/lib/src/flutter/scrollable_positioned_list/src/wrapping.dart b/lib/src/flutter/scrollable_positioned_list/src/wrapping.dart index 38d2c21e..c6b5ef43 100644 --- a/lib/src/flutter/scrollable_positioned_list/src/wrapping.dart +++ b/lib/src/flutter/scrollable_positioned_list/src/wrapping.dart @@ -165,6 +165,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { _maxScrollExtent = 0.0; _hasVisualOverflow = false; offset.applyContentDimensions(0.0, 0.0); + return; } @@ -177,6 +178,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { assert(constraints.hasBoundedWidth); size = Size(constraints.maxWidth, constraints.minHeight); break; + case Axis.horizontal: assert(constraints.hasBoundedHeight); size = Size(constraints.minWidth, constraints.maxHeight); @@ -187,6 +189,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { _shrinkWrapExtent = 0.0; _hasVisualOverflow = false; offset.applyContentDimensions(0.0, 0.0); + return; } @@ -198,6 +201,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { mainAxisExtent = constraints.maxHeight; crossAxisExtent = constraints.maxWidth; break; + case Axis.horizontal: assert(constraints.hasBoundedHeight); mainAxisExtent = constraints.maxWidth; @@ -226,6 +230,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { case Axis.vertical: effectiveExtent = constraints.constrainHeight(_shrinkWrapExtent); break; + case Axis.horizontal: effectiveExtent = constraints.constrainWidth(_shrinkWrapExtent); break; @@ -251,6 +256,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { size = constraints.constrainDimensions(crossAxisExtent, effectiveExtent); break; + case Axis.horizontal: size = constraints.constrainDimensions(effectiveExtent, crossAxisExtent); @@ -286,6 +292,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { case CacheExtentStyle.pixel: _calculatedCacheExtent = cacheExtent; break; + case CacheExtentStyle.viewport: _calculatedCacheExtent = mainAxisExtent * cacheExtent!; break; @@ -350,6 +357,7 @@ class CustomRenderShrinkWrappingViewport extends CustomRenderViewport { case GrowthDirection.forward: _maxScrollExtent += childLayoutGeometry.scrollExtent; break; + case GrowthDirection.reverse: _minScrollExtent -= childLayoutGeometry.scrollExtent; break; @@ -506,8 +514,10 @@ abstract class CustomViewport extends MultiChildRenderObjectWidget { ), ); return textDirectionToAxisDirection(Directionality.of(context)); + case AxisDirection.right: return AxisDirection.down; + case AxisDirection.down: assert( debugCheckHasDirectionality( @@ -519,6 +529,7 @@ abstract class CustomViewport extends MultiChildRenderObjectWidget { ), ); return textDirectionToAxisDirection(Directionality.of(context)); + case AxisDirection.left: return AxisDirection.down; } @@ -603,6 +614,7 @@ class ViewportElement extends MultiChildRenderObjectElement { void debugVisitOnstageChildren(ElementVisitor visitor) { children.where((Element e) { final RenderSliver renderSliver = e.renderObject! as RenderSliver; + return renderSliver.geometry!.visible; }).forEach(visitor); } @@ -793,6 +805,7 @@ abstract class CustomRenderViewport 'horizontal space in which to expand.'); } break; + case Axis.horizontal: if (!constraints.hasBoundedWidth) { throw FlutterError.fromParts([ @@ -822,8 +835,10 @@ abstract class CustomRenderViewport break; } } + return true; }()); + return constraints.biggest; } @@ -846,6 +861,7 @@ abstract class CustomRenderViewport case GrowthDirection.forward: _maxScrollExtent += childLayoutGeometry.scrollExtent; break; + case GrowthDirection.reverse: _minScrollExtent -= childLayoutGeometry.scrollExtent; break; @@ -869,6 +885,7 @@ abstract class CustomRenderViewport Offset paintOffsetOf(RenderSliver child) { final CustomSliverPhysicalContainerParentData childParentData = child.parentData! as CustomSliverPhysicalContainerParentData; + return computeAbsolutePaintOffset( child, childParentData.layoutOffset!, @@ -889,6 +906,7 @@ abstract class CustomRenderViewport current = childAfter(current); } return scrollOffsetToChild + scrollOffsetWithinChild; + case GrowthDirection.reverse: double scrollOffsetToChild = 0.0; RenderSliver? current = childBefore(center!); @@ -913,6 +931,7 @@ abstract class CustomRenderViewport current = childAfter(current); } return pinnedExtent; + case GrowthDirection.reverse: double pinnedExtent = 0.0; RenderSliver? current = childBefore(center!); @@ -927,7 +946,7 @@ abstract class CustomRenderViewport @override void applyPaintTransform(RenderObject child, Matrix4 transform) { final Offset offset = paintOffsetOf(child as RenderSliver); - transform.translate(offset.dx, offset.dy); + transform.leftTranslateByDouble(offset.dx, offset.dy, 0.0, 1.0); } @override @@ -944,9 +963,11 @@ abstract class CustomRenderViewport case AxisDirection.down: case AxisDirection.right: return parentMainAxisPosition - childParentData.layoutOffset!; + case AxisDirection.up: return (size.height - parentMainAxisPosition) - childParentData.layoutOffset!; + case AxisDirection.left: return (size.width - parentMainAxisPosition) - childParentData.layoutOffset!; @@ -964,12 +985,14 @@ abstract class CustomRenderViewport count -= 1; child = childBefore(child!); } + return count; } @override String labelForChild(int index) { if (index == 0) return 'center child'; + return 'child $index'; } diff --git a/lib/src/history/undo_manager.dart b/lib/src/history/undo_manager.dart index c0ef15a1..f7badf48 100644 --- a/lib/src/history/undo_manager.dart +++ b/lib/src/history/undo_manager.dart @@ -46,6 +46,7 @@ final class HistoryItem extends LinkedListEntry { } builder.afterSelection = beforeSelection; builder.beforeSelection = afterSelection; + return builder; } } @@ -98,6 +99,7 @@ class UndoManager { if (undoStack.isEmpty) { final item = HistoryItem(); undoStack.push(item); + return item; } final last = undoStack.last; @@ -105,8 +107,10 @@ class UndoManager { redoStack.clear(); final item = HistoryItem(); undoStack.push(item); + return item; } + return last; } diff --git a/lib/src/infra/clipboard.dart b/lib/src/infra/clipboard.dart index 63227597..ba302a2c 100644 --- a/lib/src/infra/clipboard.dart +++ b/lib/src/infra/clipboard.dart @@ -39,6 +39,7 @@ class AppFlowyClipboard { } final data = await Clipboard.getData(Clipboard.kTextPlain); + return AppFlowyClipboardData( text: data?.text, html: null, diff --git a/lib/src/infra/flowy_svg.dart b/lib/src/infra/flowy_svg.dart index bd88038d..b8a65df2 100644 --- a/lib/src/infra/flowy_svg.dart +++ b/lib/src/infra/flowy_svg.dart @@ -30,6 +30,7 @@ class EditorSvg extends StatelessWidget { context.read()?.editorStyle.textScaleFactor ?? 1.0; final height = (this.height ?? _defaultHeight) * scaleFactor; final width = (this.width ?? _defaultWidth) * scaleFactor; + return Padding( padding: padding ?? const EdgeInsets.all(0), child: _buildSvg( @@ -56,12 +57,14 @@ class EditorSvg extends StatelessWidget { } else if (number != null) { final numberText = '$number.'; + return SvgPicture.string( numberText, width: width, height: height, ); } + return Container(); } } diff --git a/lib/src/infra/log.dart b/lib/src/infra/log.dart index 7259e398..1f97b560 100644 --- a/lib/src/infra/log.dart +++ b/lib/src/infra/log.dart @@ -35,6 +35,7 @@ class AppFlowyLogConfiguration { AppFlowyEditorLogLevel _level = AppFlowyEditorLogLevel.off; AppFlowyEditorLogLevel get level => _level; + set level(AppFlowyEditorLogLevel level) { _level = level; Logger.root.level = level.toLevel(); @@ -87,8 +88,11 @@ class AppFlowyEditorLog { static AppFlowyEditorLog ui = AppFlowyEditorLog._(name: 'ui'); void error(String message) => _logger.severe(message); + void warn(String message) => _logger.warning(message); + void info(String message) => _logger.info(message); + void debug(String message) => _logger.fine(message); } @@ -97,14 +101,19 @@ extension on AppFlowyEditorLogLevel { switch (this) { case AppFlowyEditorLogLevel.off: return Level.OFF; + case AppFlowyEditorLogLevel.error: return Level.SEVERE; + case AppFlowyEditorLogLevel.warn: return Level.WARNING; + case AppFlowyEditorLogLevel.info: return Level.INFO; + case AppFlowyEditorLogLevel.debug: return Level.FINE; + case AppFlowyEditorLogLevel.all: return Level.ALL; } @@ -114,14 +123,19 @@ extension on AppFlowyEditorLogLevel { switch (this) { case AppFlowyEditorLogLevel.off: return 'OFF'; + case AppFlowyEditorLogLevel.error: return 'ERROR'; + case AppFlowyEditorLogLevel.warn: return 'WARN'; + case AppFlowyEditorLogLevel.info: return 'INFO'; + case AppFlowyEditorLogLevel.debug: return 'DEBUG'; + case AppFlowyEditorLogLevel.all: return 'ALL'; } @@ -139,6 +153,7 @@ extension on Level { } else if (this == Level.FINE) { return AppFlowyEditorLogLevel.debug; } + return AppFlowyEditorLogLevel.off; } } diff --git a/lib/src/plugins/blocks/columns/column_block_component.dart b/lib/src/plugins/blocks/columns/column_block_component.dart index 431f00db..09323d11 100644 --- a/lib/src/plugins/blocks/columns/column_block_component.dart +++ b/lib/src/plugins/blocks/columns/column_block_component.dart @@ -30,6 +30,7 @@ class ColumnBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return ColumnBlockComponent( key: node.key, node: node, @@ -135,6 +136,7 @@ class ColumnBlockComponentState extends State Selection.collapsed(position), shiftWithBaseOffset: shiftWithBaseOffset, ); + return rects.firstOrNull; } @@ -154,6 +156,7 @@ class ColumnBlockComponentState extends State renderBox.size, ]; } + return [Offset.zero & _renderBox!.size]; } diff --git a/lib/src/plugins/blocks/columns/columns_block_component.dart b/lib/src/plugins/blocks/columns/columns_block_component.dart index 8275f40d..4937c2c2 100644 --- a/lib/src/plugins/blocks/columns/columns_block_component.dart +++ b/lib/src/plugins/blocks/columns/columns_block_component.dart @@ -38,6 +38,7 @@ class ColumnsBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return ColumnsBlockComponent( key: node.key, node: node, @@ -140,6 +141,7 @@ class ColumnsBlockComponentState extends State ); } } + return children; } @@ -174,6 +176,7 @@ class ColumnsBlockComponentState extends State Selection.collapsed(position), shiftWithBaseOffset: shiftWithBaseOffset, ); + return rects.firstOrNull; } @@ -193,6 +196,7 @@ class ColumnsBlockComponentState extends State renderBox.size, ]; } + return [Offset.zero & _renderBox!.size]; } diff --git a/lib/src/plugins/html/encoder/delta_html_encoder.dart b/lib/src/plugins/html/encoder/delta_html_encoder.dart index 96209a00..0785de75 100644 --- a/lib/src/plugins/html/encoder/delta_html_encoder.dart +++ b/lib/src/plugins/html/encoder/delta_html_encoder.dart @@ -63,6 +63,7 @@ class DeltaHTMLEncoder extends Converter> { }; final tag = keyToTag[attributes.keys.first]; + return dom.Element.tag(tag)..append(domText); } @@ -81,6 +82,7 @@ class DeltaHTMLEncoder extends Converter> { span.attributes['style'] = cssString; } span.append(dom.Text(text)); + return span; } diff --git a/lib/src/plugins/html/encoder/parser/bulleted_list_node_parser.dart b/lib/src/plugins/html/encoder/parser/bulleted_list_node_parser.dart index 7c31ab2f..16ff359c 100644 --- a/lib/src/plugins/html/encoder/parser/bulleted_list_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/bulleted_list_node_parser.dart @@ -49,6 +49,7 @@ class HTMLBulletedListNodeParser extends HTMLNodeParser { HTMLTags.list, childNodes: domNodes, ); + return [element]; } } diff --git a/lib/src/plugins/html/encoder/parser/heading_node_parser.dart b/lib/src/plugins/html/encoder/parser/heading_node_parser.dart index 875c7382..021c589c 100644 --- a/lib/src/plugins/html/encoder/parser/heading_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/heading_node_parser.dart @@ -30,6 +30,7 @@ class HTMLHeadingNodeParser extends HTMLNodeParser { final tagName = 'h${node.attributes[HeadingBlockKeys.level]}'; final element = wrapChildrenNodesWithTagName(tagName, childNodes: convertedNodes); + return [element]; } } diff --git a/lib/src/plugins/html/encoder/parser/html_node_parser.dart b/lib/src/plugins/html/encoder/parser/html_node_parser.dart index 0a8e6f73..bb2224ce 100644 --- a/lib/src/plugins/html/encoder/parser/html_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/html_node_parser.dart @@ -30,6 +30,7 @@ abstract class HTMLNodeParser { for (final node in childNodes) { p.append(node); } + return p; } @@ -49,6 +50,7 @@ abstract class HTMLNodeParser { ); } } + return result; } diff --git a/lib/src/plugins/html/encoder/parser/numbered_list_node_parser.dart b/lib/src/plugins/html/encoder/parser/numbered_list_node_parser.dart index ae78cfb7..b998bab7 100644 --- a/lib/src/plugins/html/encoder/parser/numbered_list_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/numbered_list_node_parser.dart @@ -47,6 +47,7 @@ class HTMLNumberedListNodeParser extends HTMLNodeParser { HTMLTags.list, childNodes: domNodes, ); + return [element]; } } diff --git a/lib/src/plugins/html/encoder/parser/quote_node_parser.dart b/lib/src/plugins/html/encoder/parser/quote_node_parser.dart index efff024b..4eb3c522 100644 --- a/lib/src/plugins/html/encoder/parser/quote_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/quote_node_parser.dart @@ -32,6 +32,7 @@ class HTMLQuoteNodeParser extends HTMLNodeParser { final element = wrapChildrenNodesWithTagName(HTMLTags.blockQuote, childNodes: domNodes); + return [element]; } } diff --git a/lib/src/plugins/html/encoder/parser/table_node_parser.dart b/lib/src/plugins/html/encoder/parser/table_node_parser.dart index 682cf1ef..f7b1d0a4 100644 --- a/lib/src/plugins/html/encoder/parser/table_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/table_node_parser.dart @@ -62,6 +62,7 @@ class HtmlTableNodeParser extends HTMLNodeParser { final element = wrapChildrenNodesWithTagName(HTMLTags.table, childNodes: domNodes); + return [ element, ]; diff --git a/lib/src/plugins/html/encoder/parser/text_node_parser.dart b/lib/src/plugins/html/encoder/parser/text_node_parser.dart index 7568b2dd..dd3b8d11 100644 --- a/lib/src/plugins/html/encoder/parser/text_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/text_node_parser.dart @@ -35,6 +35,7 @@ class HTMLTextNodeParser extends HTMLNodeParser { } final element = wrapChildrenNodesWithTagName(HTMLTags.paragraph, childNodes: domNodes); + return [element]; } } diff --git a/lib/src/plugins/html/encoder/parser/todo_list_node_parser.dart b/lib/src/plugins/html/encoder/parser/todo_list_node_parser.dart index 5d31f670..421a5d11 100644 --- a/lib/src/plugins/html/encoder/parser/todo_list_node_parser.dart +++ b/lib/src/plugins/html/encoder/parser/todo_list_node_parser.dart @@ -38,6 +38,7 @@ class HTMLTodoListNodeParser extends HTMLNodeParser { final element = wrapChildrenNodesWithTagName(HTMLTags.div, childNodes: domNodes); + return [element]; } } diff --git a/lib/src/plugins/html/html_document_decoder.dart b/lib/src/plugins/html/html_document_decoder.dart index cb9adfdb..161aca0a 100644 --- a/lib/src/plugins/html/html_document_decoder.dart +++ b/lib/src/plugins/html/html_document_decoder.dart @@ -37,6 +37,7 @@ class DocumentHTMLDecoder extends Converter { /// this method needs to be removed in the future as it is not stable final parseForSingleChild = body.children.length == 1 && HTMLTags.formattingElements.contains(body.children.first.localName); + return Document.blank(withInitialText: false) ..insert( [0], @@ -99,6 +100,7 @@ class DocumentHTMLDecoder extends Converter { if (delta.isNotEmpty) { nodes.add(paragraphNode(delta: delta)); } + return nodes; } @@ -110,22 +112,31 @@ class DocumentHTMLDecoder extends Converter { switch (localName) { case HTMLTags.h1: return _parseHeadingElement(element, level: 1); + case HTMLTags.h2: return _parseHeadingElement(element, level: 2); + case HTMLTags.h3: return _parseHeadingElement(element, level: 3); + case HTMLTags.h4: return _parseHeadingElement(element, level: 4); + case HTMLTags.h5: return _parseHeadingElement(element, level: 5); + case HTMLTags.h6: return _parseHeadingElement(element, level: 6); + case HTMLTags.unorderedList: return _parseUnOrderListElement(element); + case HTMLTags.orderedList: return _parseOrderListElement(element); + case HTMLTags.table: return _parseTable(element); + case HTMLTags.list: return [ _parseListElement( @@ -133,12 +144,16 @@ class DocumentHTMLDecoder extends Converter { type: type, ), ]; + case HTMLTags.paragraph: return _parseParagraphElement(element); + case HTMLTags.blockQuote: return [_parseBlockQuoteElement(element)]; + case HTMLTags.image: return [_parseImageElement(element)]; + default: return _parseParagraphElement(element); } @@ -186,6 +201,7 @@ class DocumentHTMLDecoder extends Converter { nodes.addAll(tabledata); rowLength++; } + return (colLength, rowLength, nodes); } @@ -239,6 +255,7 @@ class DocumentHTMLDecoder extends Converter { } else { nodes.addAll(_parseTableDataElementsData(element)); } + return nodes; } @@ -269,6 +286,7 @@ class DocumentHTMLDecoder extends Converter { if (delta.isNotEmpty) { nodes.add(paragraphNode(delta: delta)); } + return nodes; } @@ -282,17 +300,22 @@ class DocumentHTMLDecoder extends Converter { case HTMLTags.bold || HTMLTags.strong: attributes = {AppFlowyRichTextKeys.bold: true}; break; + case HTMLTags.italic || HTMLTags.em: attributes = {AppFlowyRichTextKeys.italic: true}; break; + case HTMLTags.underline: attributes = {AppFlowyRichTextKeys.underline: true}; break; + case HTMLTags.del: attributes = {AppFlowyRichTextKeys.strikethrough: true}; break; + case HTMLTags.code: attributes = {AppFlowyRichTextKeys.code: true}; + case HTMLTags.span || HTMLTags.mark: final deltaAttributes = _getDeltaAttributesFromHTMLAttributes( element.attributes, @@ -300,6 +323,7 @@ class DocumentHTMLDecoder extends Converter { {}; attributes.addAll(deltaAttributes); break; + case HTMLTags.anchor: final href = element.attributes['href']; if (href != null) { @@ -310,12 +334,14 @@ class DocumentHTMLDecoder extends Converter { case HTMLTags.strikethrough: attributes = {AppFlowyRichTextKeys.strikethrough: true}; break; + default: break; } for (final child in element.children) { attributes.addAll(_parserFormattingElementAttributes(child)); } + return attributes; } @@ -324,6 +350,7 @@ class DocumentHTMLDecoder extends Converter { required int level, }) { final (delta, specialNodes) = _parseDeltaElement(element); + return [ headingNode( level: level, @@ -335,6 +362,7 @@ class DocumentHTMLDecoder extends Converter { Node _parseBlockQuoteElement(dom.Element element) { final (delta, nodes) = _parseDeltaElement(element); + return quoteNode( delta: delta, children: nodes, @@ -377,9 +405,11 @@ class DocumentHTMLDecoder extends Converter { if (HTMLTags.specialElements.contains(child.localName)) { return _parseSpecialElements(child, type: type); } + return []; }).toList(); } + return Node( type: type, children: node, @@ -389,6 +419,7 @@ class DocumentHTMLDecoder extends Converter { Iterable _parseParagraphElement(dom.Element element) { final (delta, specialNodes) = _parseDeltaElement(element); + return [paragraphNode(delta: delta), ...specialNodes]; } @@ -443,6 +474,7 @@ class DocumentHTMLDecoder extends Converter { delta.insert(child.text?.replaceAll(RegExp(r'\n+$'), '') ?? ''); } } + return (delta, nodes); } @@ -475,9 +507,11 @@ class DocumentHTMLDecoder extends Converter { case 'underline': attributes[AppFlowyRichTextKeys.underline] = true; break; + case 'line-through': attributes[AppFlowyRichTextKeys.strikethrough] = true; break; + default: break; } @@ -533,6 +567,7 @@ class DocumentHTMLDecoder extends Converter { } result[tuples[0].trim()] = tuples[1].trim(); } + return result; } } diff --git a/lib/src/plugins/html/html_document_encoder.dart b/lib/src/plugins/html/html_document_encoder.dart index 3a804920..b1f4ce7a 100644 --- a/lib/src/plugins/html/html_document_encoder.dart +++ b/lib/src/plugins/html/html_document_encoder.dart @@ -23,6 +23,7 @@ class DocumentHTMLEncoder extends Converter { ); } } + return buffer.toString(); } } diff --git a/lib/src/plugins/markdown/decoder/custom_syntaxes/formula_syntax.dart b/lib/src/plugins/markdown/decoder/custom_syntaxes/formula_syntax.dart index a616d6a1..e9c544e8 100644 --- a/lib/src/plugins/markdown/decoder/custom_syntaxes/formula_syntax.dart +++ b/lib/src/plugins/markdown/decoder/custom_syntaxes/formula_syntax.dart @@ -13,6 +13,7 @@ class FormulaInlineSyntax extends md.InlineSyntax { final element = md.Element('formula', [md.Text('\$')]); element.attributes['formula'] = formula; parser.addNode(element); + return true; } } diff --git a/lib/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart b/lib/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart index 1079c727..e724e684 100644 --- a/lib/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart +++ b/lib/src/plugins/markdown/decoder/custom_syntaxes/underline_syntax.dart @@ -8,6 +8,7 @@ class UnderlineInlineSyntax extends md.InlineSyntax { final text = match.group(1) ?? ''; List nestedNodes = md.InlineParser(text, parser.document).parse(); parser.addNode(md.Element('u', nestedNodes)); + return true; } } diff --git a/lib/src/plugins/markdown/decoder/delta_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/delta_markdown_decoder.dart index f37b525b..eb959061 100644 --- a/lib/src/plugins/markdown/decoder/delta_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/delta_markdown_decoder.dart @@ -33,6 +33,7 @@ class DeltaMarkdownDecoder extends Converter for (final node in document) { node.accept(this); } + return _delta; } @@ -44,6 +45,7 @@ class DeltaMarkdownDecoder extends Converter for (final node in nodes) { node.accept(this); } + return _delta; } @@ -55,6 +57,7 @@ class DeltaMarkdownDecoder extends Converter @override bool visitElementBefore(md.Element element) { _addAttributeKey(element); + return true; } diff --git a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart index d44d48dc..505b24c2 100644 --- a/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart +++ b/lib/src/plugins/markdown/decoder/document_markdown_decoder.dart @@ -74,6 +74,7 @@ class DocumentMarkdownDecoder extends Converter { final text = match[1] ?? ''; final altText = match[2] ?? ''; final url = match[3] ?? ''; + return '$text\n\n![$altText]($url)'; }, ); diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart index bdb4dbdf..2015dd37 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_block_quote_parser.dart @@ -20,6 +20,7 @@ class MarkdownBlockQuoteParserV2 extends CustomMarkdownParser { } final deltaDecoder = DeltaMarkdownDecoder(); + return [ quoteNode( delta: deltaDecoder.convertNodes(element.children), diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart index fdb6fd3c..8d7807b1 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_heading_parser.dart @@ -24,6 +24,7 @@ class MarkdownHeadingParserV2 extends CustomMarkdownParser { final level = _headingTags.indexOf(element.tag) + 1; final deltaDecoder = DeltaMarkdownDecoder(); + return [ headingNode( level: level, diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart index bec3e12f..06502bfd 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_paragraph_parser.dart @@ -42,6 +42,7 @@ class MarkdownParagraphParserV2 extends CustomMarkdownParser { return splitContent.map((content) { final deltaDecoder = DeltaMarkdownDecoder(); final delta = deltaDecoder.convertNodes(content); + return paragraphNode(delta: delta); }).toList(); @@ -72,6 +73,7 @@ List> _splitByBrTag(List nodes) { } else { acc.last.add(node); } + return acc; }, ) diff --git a/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart b/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart index 3b353e70..235cffa2 100644 --- a/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart +++ b/lib/src/plugins/markdown/decoder/parser/markdown_todo_list_parser.dart @@ -38,6 +38,7 @@ class MarkdownTodoListParserV2 extends CustomMarkdownParser { } final deltaDecoder = DeltaMarkdownDecoder(); + return [ todoListNode( checked: checked, diff --git a/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart b/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart index f5eae915..8e297a9e 100644 --- a/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart +++ b/lib/src/plugins/markdown/encoder/delta_markdown_encoder.dart @@ -28,6 +28,7 @@ class DeltaMarkdownEncoder extends Converter { } } } + return buffer.toString(); } diff --git a/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart b/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart index 19a5a9c6..1a276860 100644 --- a/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart +++ b/lib/src/plugins/markdown/encoder/document_markdown_encoder.dart @@ -26,6 +26,7 @@ class DocumentMarkdownEncoder extends Converter { } } } + return buffer.toString(); } @@ -40,6 +41,7 @@ class DocumentMarkdownEncoder extends Converter { .map((e) => e.isNotEmpty ? '\t$e' : e) .join('\n'); } + return result; } } diff --git a/lib/src/plugins/markdown/encoder/parser/bulleted_list_node_parser.dart b/lib/src/plugins/markdown/encoder/parser/bulleted_list_node_parser.dart index 1147773e..9348d8cc 100644 --- a/lib/src/plugins/markdown/encoder/parser/bulleted_list_node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/bulleted_list_node_parser.dart @@ -15,6 +15,7 @@ class BulletedListNodeParser extends NodeParser { if (children != null && children.isNotEmpty) { markdown += children; } + return markdown; } } diff --git a/lib/src/plugins/markdown/encoder/parser/node_parser.dart b/lib/src/plugins/markdown/encoder/parser/node_parser.dart index 64a02aea..1041150d 100644 --- a/lib/src/plugins/markdown/encoder/parser/node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/node_parser.dart @@ -4,5 +4,6 @@ abstract class NodeParser { const NodeParser(); String get id; + String transform(Node node, DocumentMarkdownEncoder? encoder); } diff --git a/lib/src/plugins/markdown/encoder/parser/numbered_list_node_parser.dart b/lib/src/plugins/markdown/encoder/parser/numbered_list_node_parser.dart index 6b9868f8..6926f22b 100644 --- a/lib/src/plugins/markdown/encoder/parser/numbered_list_node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/numbered_list_node_parser.dart @@ -16,6 +16,7 @@ class NumberedListNodeParser extends NodeParser { if (children != null && children.isNotEmpty) { markdown += children; } + return markdown; } } diff --git a/lib/src/plugins/markdown/encoder/parser/quote_node_parser.dart b/lib/src/plugins/markdown/encoder/parser/quote_node_parser.dart index bc97294a..744d64a3 100644 --- a/lib/src/plugins/markdown/encoder/parser/quote_node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/quote_node_parser.dart @@ -15,6 +15,7 @@ class QuoteNodeParser extends NodeParser { if (children != null && children.isNotEmpty) { markdown += children; } + return markdown; } } diff --git a/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart b/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart index 8d3d0a07..251235fa 100644 --- a/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/text_node_parser.dart @@ -22,6 +22,7 @@ class TextNodeParser extends NodeParser { if (children != null && children.isNotEmpty) { markdown += children; } + return markdown; } } diff --git a/lib/src/plugins/markdown/encoder/parser/todo_list_node_parser.dart b/lib/src/plugins/markdown/encoder/parser/todo_list_node_parser.dart index 7c1cb12e..86fade82 100644 --- a/lib/src/plugins/markdown/encoder/parser/todo_list_node_parser.dart +++ b/lib/src/plugins/markdown/encoder/parser/todo_list_node_parser.dart @@ -17,6 +17,7 @@ class TodoListNodeParser extends NodeParser { if (children != null && children.isNotEmpty) { markdown += children; } + return markdown; } } diff --git a/lib/src/plugins/pdf/html_to_pdf_encoder.dart b/lib/src/plugins/pdf/html_to_pdf_encoder.dart index 0efd5e26..d88b8aae 100644 --- a/lib/src/plugins/pdf/html_to_pdf_encoder.dart +++ b/lib/src/plugins/pdf/html_to_pdf_encoder.dart @@ -44,6 +44,7 @@ class PdfHTMLEncoder { }, ), ); + return blank; } final nodes = await _parseElement(body.nodes); @@ -51,6 +52,7 @@ class PdfHTMLEncoder { newPdf.addPage( pw.MultiPage(build: (pw.Context context) => nodes.toList()), ); + return newPdf; } @@ -142,6 +144,7 @@ class PdfHTMLEncoder { ), ); } + return nodes; } @@ -153,22 +156,31 @@ class PdfHTMLEncoder { switch (localName) { case HTMLTags.h1: return [_parseHeadingElement(element, level: 1)]; + case HTMLTags.h2: return [_parseHeadingElement(element, level: 2)]; + case HTMLTags.h3: return [_parseHeadingElement(element, level: 3)]; + case HTMLTags.h4: return [_parseHeadingElement(element, level: 4)]; + case HTMLTags.h5: return [_parseHeadingElement(element, level: 5)]; + case HTMLTags.h6: return [_parseHeadingElement(element, level: 6)]; + case HTMLTags.unorderedList: return _parseUnOrderListElement(element); + case HTMLTags.orderedList: return _parseOrderListElement(element); + case HTMLTags.table: return _parseRawTableData(element); + case HTMLTags.list: return [ _parseListElement( @@ -176,10 +188,13 @@ class PdfHTMLEncoder { type: type, ), ]; + case HTMLTags.paragraph: return [await _parseParagraphElement(element)]; + case HTMLTags.image: return [await _parseImageElement(element)]; + default: return [await _parseParagraphElement(element)]; } @@ -227,6 +242,7 @@ class PdfHTMLEncoder { } tableRows.add(pw.TableRow(children: rowData)); } + return [ pw.Table( children: tableRows, @@ -253,9 +269,11 @@ class PdfHTMLEncoder { case HTMLTags.em: attributes = attributes.copyWith(fontStyle: pw.FontStyle.italic); break; + case HTMLTags.underline: decoration.add(pw.TextDecoration.underline); break; + case HTMLTags.del: attributes = attributes.copyWith(decoration: pw.TextDecoration.lineThrough); @@ -276,11 +294,13 @@ class PdfHTMLEncoder { attributes = attributes.copyWith(color: pdf.PdfColors.blue); } break; + case HTMLTags.code: attributes = attributes.copyWith( background: const pw.BoxDecoration(color: pdf.PdfColors.grey), ); break; + default: break; } @@ -292,6 +312,7 @@ class PdfHTMLEncoder { textAlign = formattedAttrs.$1; } } + return ( textAlign, attributes.copyWith(decoration: pw.TextDecoration.combine(decoration)) @@ -324,6 +345,7 @@ class PdfHTMLEncoder { ); } } + return pw.Header( level: level, child: pw.RichText( @@ -386,6 +408,7 @@ class PdfHTMLEncoder { if (element.text.contains('[x]')) { condition = true; } + return pw.Row( children: [ pw.Checkbox( @@ -418,9 +441,11 @@ class PdfHTMLEncoder { if (src != null) { if (src.startsWith('https')) { final networkImage = await _fetchImage(src); + return pw.Image(pw.MemoryImage(networkImage)); } else { File localImage = File(src); + return pw.Image(pw.MemoryImage(await localImage.readAsBytes())); } } else { @@ -434,6 +459,7 @@ class PdfHTMLEncoder { Future _fetchImage(String url) async { try { final Response response = await get(Uri.parse(url)); + return response.bodyBytes; } catch (e) { throw Exception(e); @@ -491,6 +517,7 @@ class PdfHTMLEncoder { ); } } + return pw.Wrap( children: [ pw.SizedBox( @@ -521,6 +548,7 @@ class PdfHTMLEncoder { textDecorations.add(pw.TextDecoration.underline); } } + return style.copyWith( decoration: pw.TextDecoration.combine( textDecorations, @@ -593,12 +621,16 @@ class PdfHTMLEncoder { switch (alignment) { case 'right': return pw.TextAlign.right; + case 'center': return pw.TextAlign.center; + case 'left': return pw.TextAlign.left; + case 'justify': return pw.TextAlign.justify; + default: return pw.TextAlign.left; } @@ -617,6 +649,7 @@ class PdfHTMLEncoder { } result[tuples[0].trim()] = tuples[1].trim(); } + return result; } } @@ -626,16 +659,22 @@ extension HeaderSize on int { switch (this) { case 1: return 32; + case 2: return 28; + case 3: return 20; + case 4: return 17; + case 5: return 14; + case 6: return 10; + default: return 32; } diff --git a/lib/src/plugins/quill_delta/quill_delta_encoder.dart b/lib/src/plugins/quill_delta/quill_delta_encoder.dart index 6bbd4c58..9a269037 100644 --- a/lib/src/plugins/quill_delta/quill_delta_encoder.dart +++ b/lib/src/plugins/quill_delta/quill_delta_encoder.dart @@ -126,6 +126,7 @@ class QuillDeltaEncoder extends Converter { delta: node.delta, ); } + return node; } @@ -134,6 +135,7 @@ class QuillDeltaEncoder extends Converter { if (header == null) { return node; } + return headingNode( delta: node.delta, level: header, @@ -158,6 +160,7 @@ class QuillDeltaEncoder extends Converter { nestedLists[0]?.add(bulletedList); } return bulletedList; + case _orderedList: final numberedList = numberedListNode( delta: node.delta, @@ -172,18 +175,21 @@ class QuillDeltaEncoder extends Converter { nestedLists[0]?.add(numberedList); } return numberedList; + case _checkedList: final checkedList = todoListNode( delta: node.delta, checked: true, ); return checkedList; + case _uncheckedList: final uncheckedList = todoListNode( delta: node.delta, checked: false, ); return uncheckedList; + default: return node; } @@ -191,17 +197,20 @@ class QuillDeltaEncoder extends Converter { int _indentLevel(Map? attributes) { final indent = attributes?['indent'] as int?; + return indent ?? 1; } bool _isIndentBulletedList(Map? attributes) { final list = attributes?[_list] as String?; final indent = attributes?[_indent] as int?; + return [_bulletedList, _orderedList].contains(list) && indent != null; } bool _containsStyle(Map? attributes, String key) { final value = attributes?[key] as bool?; + return value == true; } @@ -213,6 +222,7 @@ class QuillDeltaEncoder extends Converter { return '0xFF${color.substring(1)}'; } else if (color.startsWith("rgba")) { List rgbaList = color.substring(5, color.length - 1).split(','); + return Color.fromRGBO( int.parse(rgbaList[0]), int.parse(rgbaList[1]), @@ -220,6 +230,7 @@ class QuillDeltaEncoder extends Converter { double.parse(rgbaList[3]), ).toHex(); } + return null; } } diff --git a/lib/src/plugins/word_count/word_counter_service.dart b/lib/src/plugins/word_count/word_counter_service.dart index ee7e71ce..fc426c50 100644 --- a/lib/src/plugins/word_count/word_counter_service.dart +++ b/lib/src/plugins/word_count/word_counter_service.dart @@ -33,9 +33,11 @@ class Counters { _charCount = charCount; final int _wordCount; + int get wordCount => _wordCount; final int _charCount; + int get charCount => _charCount; @override @@ -195,6 +197,7 @@ class WordCountService with ChangeNotifier { } _selectionCounters = const Counters(); + return notifyListeners(); } diff --git a/lib/src/render/color_menu/color_picker.dart b/lib/src/render/color_menu/color_picker.dart index 268e94cd..9c508c94 100644 --- a/lib/src/render/color_menu/color_picker.dart +++ b/lib/src/render/color_menu/color_picker.dart @@ -33,11 +33,13 @@ class ColorOptionList { if (colorHex == null) return null; final opacityHex = colorHex.substring(2, 4); final opacity = int.parse(opacityHex, radix: 16) / 2.55; + return opacity.toStringAsFixed(0); } String? _extractColorHex(String? colorHex) { if (colorHex == null) return null; + return colorHex.substring(4); } } @@ -268,6 +270,7 @@ class _ColorPickerState extends State { colorHex = _fixColorHex(colorHex); opacity = _fixOpacity(opacity); final opacityHex = (int.parse(opacity) * 2.55).round().toRadixString(16); + return '0x$opacityHex$colorHex'; } @@ -278,6 +281,7 @@ class _ColorPickerState extends State { if (int.tryParse(colorHex, radix: 16) == null) { colorHex = 'FFFFFF'; } + return colorHex; } @@ -288,6 +292,7 @@ class _ColorPickerState extends State { int.parse(opacity) < 0) { return '100'; } + return opacity; } } diff --git a/lib/src/render/selection/cursor.dart b/lib/src/render/selection/cursor.dart index e4c6c4dc..a2655a01 100644 --- a/lib/src/render/selection/cursor.dart +++ b/lib/src/render/selection/cursor.dart @@ -76,12 +76,14 @@ class CursorState extends State { return Container( color: color, ); + case CursorStyle.borderLine: return Container( decoration: BoxDecoration( border: Border.all(color: color, width: 2), ), ); + case CursorStyle.cover: final size = widget.rect.size; return Container( diff --git a/lib/src/render/selection/mobile_basic_handle.dart b/lib/src/render/selection/mobile_basic_handle.dart index f4cd724a..72ea6cb9 100644 --- a/lib/src/render/selection/mobile_basic_handle.dart +++ b/lib/src/render/selection/mobile_basic_handle.dart @@ -22,10 +22,13 @@ enum HandleType { switch (this) { case HandleType.none: throw UnsupportedError('Unsupported handle type'); + case HandleType.left: return MobileSelectionDragMode.leftSelectionHandle; + case HandleType.right: return MobileSelectionDragMode.rightSelectionHandle; + case HandleType.collapsed: return MobileSelectionDragMode.cursor; } @@ -35,10 +38,13 @@ enum HandleType { switch (this) { case HandleType.none: throw UnsupportedError('Unsupported handle type'); + case HandleType.left: return CrossAxisAlignment.end; + case HandleType.right: return CrossAxisAlignment.start; + case HandleType.collapsed: return CrossAxisAlignment.center; } @@ -48,10 +54,13 @@ enum HandleType { switch (this) { case HandleType.none: throw UnsupportedError('Unsupported handle type'); + case HandleType.left: return _leftHandleKey; + case HandleType.right: return _rightHandleKey; + case HandleType.collapsed: return _collapsedHandleKey; } diff --git a/lib/src/render/selection/mobile_collapsed_handle.dart b/lib/src/render/selection/mobile_collapsed_handle.dart index 98979f54..f5330132 100644 --- a/lib/src/render/selection/mobile_collapsed_handle.dart +++ b/lib/src/render/selection/mobile_collapsed_handle.dart @@ -85,6 +85,7 @@ class _IOSCollapsedHandle extends StatelessWidget { rect.width + widthExtend, rect.height + heightExtend, ); + return Positioned.fromRect( rect: adjustedRect, child: CompositedTransformFollower( @@ -148,6 +149,7 @@ class _AndroidCollapsedHandle extends StatelessWidget { rect.width + widthExtend, rect.height + heightExtend, ); + return Positioned.fromRect( rect: adjustedRect, child: CompositedTransformFollower( diff --git a/lib/src/render/selection/selectable.dart b/lib/src/render/selection/selectable.dart index e903bbb5..83e502f4 100644 --- a/lib/src/render/selection/selectable.dart +++ b/lib/src/render/selection/selectable.dart @@ -98,6 +98,7 @@ mixin SelectableMixin on State { r.topLeft, shiftWithBaseOffset: shiftWithBaseOffset, ); + return Rect.fromLTWH(topLeft.dx, topLeft.dy, r.width, r.height); } diff --git a/lib/src/render/toolbar/toolbar_item.dart b/lib/src/render/toolbar/toolbar_item.dart index a16fcffb..5d0fac35 100644 --- a/lib/src/render/toolbar/toolbar_item.dart +++ b/lib/src/render/toolbar/toolbar_item.dart @@ -68,6 +68,7 @@ class ToolbarItem { if (identical(this, other)) { return true; } + return id == other.id; } @@ -93,6 +94,7 @@ bool onlyShowInSingleSelectionAndTextType(EditorState editorState) { if (node == null) { return false; } + return node.delta != null && toolbarItemWhiteList.contains(node.type); } @@ -102,6 +104,7 @@ bool onlyShowInTextType(EditorState editorState) { return false; } final nodes = editorState.getNodesInSelection(selection); + return nodes.every( (node) => node.delta != null && toolbarItemWhiteList.contains(node.type), ); diff --git a/lib/src/render/toolbar/toolbar_item_widget.dart b/lib/src/render/toolbar/toolbar_item_widget.dart index e193ca3f..bf266463 100644 --- a/lib/src/render/toolbar/toolbar_item_widget.dart +++ b/lib/src/render/toolbar/toolbar_item_widget.dart @@ -38,6 +38,7 @@ class ToolbarItemWidget extends StatelessWidget { ), ); } + return const SizedBox.shrink(); } } diff --git a/lib/src/service/default_text_operations/format_rich_text_style.dart b/lib/src/service/default_text_operations/format_rich_text_style.dart index a1e6941c..fab5a3d3 100644 --- a/lib/src/service/default_text_operations/format_rich_text_style.dart +++ b/lib/src/service/default_text_operations/format_rich_text_style.dart @@ -69,5 +69,6 @@ bool insertNodeAfterSelection( } editorState.apply(transaction); + return true; } diff --git a/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart b/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart index 7bc16f35..3aa70c80 100644 --- a/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart +++ b/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart @@ -51,6 +51,7 @@ void _pasteMarkdown(EditorState editorState, String markdown) { if (lines.length == 1) { _pasteSingleLine(editorState, selection, lines[0]); + return; } @@ -108,6 +109,7 @@ void pasteHTML(EditorState editorState, String html) { if (delta == null) { return true; } + return delta.isNotEmpty; }); if (htmlToNodes.isEmpty) { @@ -138,6 +140,7 @@ Selection _computeSelectionAfterPasteMultipleNodes( final currentPath = [...currentCursor.path]; currentPath[currentPath.length - 1] += nodes.length; final int lenOfLastNode = _textLengthOfNode(nodes.last); + return Selection.collapsed( Position(path: currentPath, offset: lenOfLastNode), ); @@ -270,6 +273,7 @@ void _pasteMultipleLinesInText( ]); transaction.afterSelection = afterSelection; editorState.apply(transaction); + return; } final path = node.path; @@ -286,6 +290,7 @@ void _pasteMultipleLinesInText( ]); transaction.afterSelection = afterSelection; editorState.apply(transaction); + return; } @@ -343,10 +348,12 @@ void handlePaste(EditorState editorState) async { void _pasteRichClipboard(EditorState editorState, AppFlowyClipboardData data) { if (data.html != null) { pasteHTML(editorState, data.html!); + return; } if (data.text != null) { handlePastePlainText(editorState, data.text!); + return; } } @@ -359,6 +366,7 @@ bool _isNodeInsideTable(Node node) { } current = current.parent; } + return false; } diff --git a/lib/src/service/internal_key_event_handlers/exit_editing_mode_handler.dart b/lib/src/service/internal_key_event_handlers/exit_editing_mode_handler.dart index 2ffe0f3b..789b1458 100644 --- a/lib/src/service/internal_key_event_handlers/exit_editing_mode_handler.dart +++ b/lib/src/service/internal_key_event_handlers/exit_editing_mode_handler.dart @@ -3,5 +3,6 @@ import 'package:flutter/material.dart'; ShortcutEventHandler exitEditingModeEventHandler = (editorState, event) { editorState.service.selectionService.clearSelection(); + return KeyEventResult.handled; }; diff --git a/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart b/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart index f10559ff..3c7d0782 100644 --- a/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart +++ b/lib/src/service/internal_key_event_handlers/page_up_down_handler.dart @@ -7,6 +7,7 @@ ShortcutEventHandler pageUpHandler = (editorState, _) { if (scrollHeight != null && scrollService != null) { scrollService.scrollTo(scrollService.dy - scrollHeight); } + return KeyEventResult.handled; }; @@ -16,5 +17,6 @@ ShortcutEventHandler pageDownHandler = (editorState, _) { if (scrollHeight != null && scrollService != null) { scrollService.scrollTo(scrollService.dy + scrollHeight); } + return KeyEventResult.handled; }; diff --git a/lib/src/service/internal_key_event_handlers/redo_undo_handler.dart b/lib/src/service/internal_key_event_handlers/redo_undo_handler.dart index e20d6dc4..15bd1a6f 100644 --- a/lib/src/service/internal_key_event_handlers/redo_undo_handler.dart +++ b/lib/src/service/internal_key_event_handlers/redo_undo_handler.dart @@ -3,10 +3,12 @@ import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handle ShortcutEventHandler redoEventHandler = (editorState, event) { editorState.undoManager.redo(); + return KeyEventResult.handled; }; ShortcutEventHandler undoEventHandler = (editorState, event) { editorState.undoManager.undo(); + return KeyEventResult.handled; }; diff --git a/lib/src/service/shortcut_event/keybinding.dart b/lib/src/service/shortcut_event/keybinding.dart index 5d83699d..88c4b253 100644 --- a/lib/src/service/shortcut_event/keybinding.dart +++ b/lib/src/service/shortcut_event/keybinding.dart @@ -16,6 +16,7 @@ extension KeybindingsExtension on List { return true; } } + return false; } } diff --git a/pubspec.yaml b/pubspec.yaml index 59ee4bf4..c5fa9217 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,11 @@ dependencies: url_launcher: "^6.1.11" dev_dependencies: + awesome_lints: + git: + url: https://github.com/LucasXu0/awesome_lints.git + ref: main + custom_lint: ^0.8.1 flutter_lints: ^6.0.0 flutter_localizations: sdk: flutter diff --git a/test/core/document/diff_test.dart b/test/core/document/diff_test.dart index 9ff6c587..18bc67c4 100644 --- a/test/core/document/diff_test.dart +++ b/test/core/document/diff_test.dart @@ -23,6 +23,7 @@ void main() async { transaction.add(op); } await editorState.apply(transaction, isRemote: true); + return editorState.document; } diff --git a/test/customer/auto_complete_test.dart b/test/customer/auto_complete_test.dart index 6ab471d7..d88ccd99 100644 --- a/test/customer/auto_complete_test.dart +++ b/test/customer/auto_complete_test.dart @@ -80,6 +80,7 @@ class AutoCompleteEditor extends StatelessWidget { if (text.toLowerCase().endsWith('hello')) { return ' world'; } + return null; }, ), diff --git a/test/customer/custom_attribute_for_text_block_test.dart b/test/customer/custom_attribute_for_text_block_test.dart index 8d4c672b..79473fed 100644 --- a/test/customer/custom_attribute_for_text_block_test.dart +++ b/test/customer/custom_attribute_for_text_block_test.dart @@ -55,6 +55,7 @@ class CustomAttributeKeyForTextBlock extends StatelessWidget { ), ); } + return textSpan; }, ); @@ -71,6 +72,7 @@ class CustomAttributeKeyForTextBlock extends StatelessWidget { }, ); final editorState = EditorState(document: document); + return MaterialApp( home: Scaffold( body: SafeArea( diff --git a/test/customer/custom_block_icon_test.dart b/test/customer/custom_block_icon_test.dart index 2298ed1f..a927b9df 100644 --- a/test/customer/custom_block_icon_test.dart +++ b/test/customer/custom_block_icon_test.dart @@ -69,6 +69,7 @@ class CustomBlockIcon extends StatelessWidget { }; final editorState = EditorState(document: document); + return MaterialApp( home: Scaffold( body: SafeArea( diff --git a/test/customer/custom_editor_directionality_test.dart b/test/customer/custom_editor_directionality_test.dart index 842b926a..5c25e027 100644 --- a/test/customer/custom_editor_directionality_test.dart +++ b/test/customer/custom_editor_directionality_test.dart @@ -41,6 +41,7 @@ class DirectionalityTester extends StatelessWidget { ); final editorState = EditorState(document: document); + return MaterialApp( home: Scaffold( body: SafeArea( diff --git a/test/customer/custom_error_block_test.dart b/test/customer/custom_error_block_test.dart index 83f80057..f5a681c5 100644 --- a/test/customer/custom_error_block_test.dart +++ b/test/customer/custom_error_block_test.dart @@ -78,6 +78,7 @@ class ErrorBlockComponentBuilder extends BlockComponentBuilder { @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { final node = blockComponentContext.node; + return ErrorBlockComponentWidget( key: node.key, node: node, diff --git a/test/customer/custom_image_menu_test.dart b/test/customer/custom_image_menu_test.dart index 5eaf1005..04246964 100644 --- a/test/customer/custom_image_menu_test.dart +++ b/test/customer/custom_image_menu_test.dart @@ -65,6 +65,7 @@ class CustomImageMenu extends StatelessWidget { }; final editorState = EditorState(document: document); + return MaterialApp( home: Scaffold( body: SafeArea( diff --git a/test/editor/editor_component/ime/non_delta_input_service_test.dart b/test/editor/editor_component/ime/non_delta_input_service_test.dart index 556e75f6..1138c4a0 100644 --- a/test/editor/editor_component/ime/non_delta_input_service_test.dart +++ b/test/editor/editor_component/ime/non_delta_input_service_test.dart @@ -156,18 +156,22 @@ void main() { final inputService = NonDeltaTextInputService( onInsert: (v) async { value = v.apply(value); + return true; }, onDelete: (v) async { value = v.apply(value); + return true; }, onReplace: (v) async { value = v.apply(value); + return true; }, onNonTextUpdate: (v) async { value = v.apply(value); + return true; }, onPerformAction: (_) async {}, diff --git a/test/editor_state_test.dart b/test/editor_state_test.dart index b9fcf635..af4f64f0 100644 --- a/test/editor_state_test.dart +++ b/test/editor_state_test.dart @@ -15,6 +15,7 @@ void main() async { case TransactionTime.before: expect(editorState.getNodeAtPath([0]), null); break; + case TransactionTime.after: expect( editorState.getNodeAtPath([0])!.type, diff --git a/test/infra/clipboard_test.dart b/test/infra/clipboard_test.dart index e12c6021..34624032 100644 --- a/test/infra/clipboard_test.dart +++ b/test/infra/clipboard_test.dart @@ -32,12 +32,14 @@ void main() { switch (message.method) { case "Clipboard.getData": return mockClipboard.getData; + case "Clipboard.setData": final args = message.arguments as Map; mockClipboard = mockClipboard.copyWith( text: args['text'], ); } + return null; }); }); diff --git a/test/mobile/toolbar/mobile/test_helpers/mobile_app_with_toolbar_widget.dart b/test/mobile/toolbar/mobile/test_helpers/mobile_app_with_toolbar_widget.dart index f56da01d..fa5fabc7 100644 --- a/test/mobile/toolbar/mobile/test_helpers/mobile_app_with_toolbar_widget.dart +++ b/test/mobile/toolbar/mobile/test_helpers/mobile_app_with_toolbar_widget.dart @@ -23,6 +23,7 @@ class MobileAppWithToolbarWidget extends StatelessWidget { quoteMobileToolbarItem, codeMobileToolbarItem, ]; + return MaterialApp( home: Column( children: [ diff --git a/test/new/command/text_commands_test.dart b/test/new/command/text_commands_test.dart index 7f242dc7..39f76701 100644 --- a/test/new/command/text_commands_test.dart +++ b/test/new/command/text_commands_test.dart @@ -62,6 +62,7 @@ void main() async { final result = after?.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); @@ -95,6 +96,7 @@ void main() async { final after = editorState.getNodesInSelection(selection); final result = after.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); diff --git a/test/new/extensions/node_extension_test.dart b/test/new/extensions/node_extension_test.dart index 0865cb83..54012ab5 100644 --- a/test/new/extensions/node_extension_test.dart +++ b/test/new/extensions/node_extension_test.dart @@ -32,6 +32,7 @@ void main() async { final node = editorState.getNodeAtPath([0]); final result = node!.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); @@ -63,6 +64,7 @@ void main() async { final node = editorState.getNodeAtPath([0]); final result = node!.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); @@ -95,6 +97,7 @@ void main() async { final node = editorState.getNodeAtPath([0]); final result = node!.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); @@ -143,6 +146,7 @@ void main() async { final nodes = editorState.getNodesInSelection(selection); final result = nodes.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); @@ -188,6 +192,7 @@ void main() async { final nodes = editorState.getNodesInSelection(selection); final result = nodes.allSatisfyInSelection(selection, (delta) { final textInserts = delta.whereType(); + return textInserts .every((element) => element.attributes?['bold'] == true); }); diff --git a/test/new/infra/testable_editor.dart b/test/new/infra/testable_editor.dart index df1f143e..6d0f8267 100644 --- a/test/new/infra/testable_editor.dart +++ b/test/new/infra/testable_editor.dart @@ -31,11 +31,13 @@ class TestableEditor { late EditorState _editorState; Document get document => _editorState.document; + int get documentRootLen => document.root.children.length; Selection? get selection => _editorState.selection; MockIMEInput? _ime; + MockIMEInput get ime { return _ime ??= MockIMEInput( editorState: editorState, @@ -166,6 +168,7 @@ class TestableEditor { ), ); await tester.pump(); + return this; } @@ -308,6 +311,7 @@ class MockIMEInput { TextInputService get imeInput { final keyboardService = tester.state(find.byType(KeyboardServiceWidget)) as KeyboardServiceWidgetState; + return keyboardService.textInputService; } diff --git a/test/new/service/shortcuts/character_shortcut_events/character_shortcut_event_test.dart b/test/new/service/shortcuts/character_shortcut_events/character_shortcut_event_test.dart index d7ba9b62..db773189 100644 --- a/test/new/service/shortcuts/character_shortcut_events/character_shortcut_event_test.dart +++ b/test/new/service/shortcuts/character_shortcut_events/character_shortcut_event_test.dart @@ -35,6 +35,7 @@ void main() async { var handlerCalled = false; Future handler(EditorState state) async { handlerCalled = true; + return true; } diff --git a/test/new/service/shortcuts/command_shortcut_events/copy_command_test.dart b/test/new/service/shortcuts/command_shortcut_events/copy_command_test.dart index e9eeebc7..3e8c6683 100644 --- a/test/new/service/shortcuts/command_shortcut_events/copy_command_test.dart +++ b/test/new/service/shortcuts/command_shortcut_events/copy_command_test.dart @@ -18,12 +18,14 @@ void main() async { switch (message.method) { case "Clipboard.getData": return mockClipboard.getData; + case "Clipboard.setData": final args = message.arguments as Map; mockClipboard = mockClipboard.copyWith( text: args['text'], ); } + return null; }); }); diff --git a/test/new/service/shortcuts/command_shortcut_events/copy_paste_handler_test.dart b/test/new/service/shortcuts/command_shortcut_events/copy_paste_handler_test.dart index d4dd3440..3a206a75 100644 --- a/test/new/service/shortcuts/command_shortcut_events/copy_paste_handler_test.dart +++ b/test/new/service/shortcuts/command_shortcut_events/copy_paste_handler_test.dart @@ -20,12 +20,14 @@ void main() async { switch (message.method) { case "Clipboard.getData": return mockClipboard.getData; + case "Clipboard.setData": final args = message.arguments as Map; mockClipboard = mockClipboard.copyWith( text: args['text'], ); } + return null; }); }); diff --git a/test/new/service/shortcuts/command_shortcut_events/paste_command_test.dart b/test/new/service/shortcuts/command_shortcut_events/paste_command_test.dart index ce3292cd..746a2b10 100644 --- a/test/new/service/shortcuts/command_shortcut_events/paste_command_test.dart +++ b/test/new/service/shortcuts/command_shortcut_events/paste_command_test.dart @@ -19,12 +19,14 @@ void main() async { switch (message.method) { case "Clipboard.getData": return mockClipboard.getData; + case "Clipboard.setData": final args = message.arguments as Map; mockClipboard = mockClipboard.copyWith( text: args['text'], ); } + return null; }); }); diff --git a/test/new/util/document_util.dart b/test/new/util/document_util.dart index 2370c23a..fdac6ef9 100644 --- a/test/new/util/document_util.dart +++ b/test/new/util/document_util.dart @@ -48,8 +48,10 @@ extension DocumentExtension on Document { node.updateAttributes({ 'delta': builder0(index).toJson(), }); + return node; }); + return this ..insert( [root.children.length], diff --git a/test/new/util/node_util.dart b/test/new/util/node_util.dart index ee911ef2..9c871189 100644 --- a/test/new/util/node_util.dart +++ b/test/new/util/node_util.dart @@ -21,6 +21,7 @@ extension NodeExtension on Node { node.updateAttributes({ 'delta': builder0(index).toJson(), }); + return node; }, ); diff --git a/test/plugins/html/html_document_test.dart b/test/plugins/html/html_document_test.dart index 938825b1..517b207d 100644 --- a/test/plugins/html/html_document_test.dart +++ b/test/plugins/html/html_document_test.dart @@ -343,6 +343,7 @@ void main() { final cleanJson = jsonList.map((e) { final map = e as Map; map.removeWhere((k, v) => k != 'insert' && k != 'attributes'); + return map; }).toList(); expect( diff --git a/test/plugins/markdown/custom_parsers/test_custom_node_parsers.dart b/test/plugins/markdown/custom_parsers/test_custom_node_parsers.dart index 5e3b2d1b..d7be4b3a 100644 --- a/test/plugins/markdown/custom_parsers/test_custom_node_parsers.dart +++ b/test/plugins/markdown/custom_parsers/test_custom_node_parsers.dart @@ -11,6 +11,7 @@ class TestCustomInlineSyntaxes extends md.InlineSyntax { "page_id":"${match.group(0)}" }'''; parser.addNode(el); + return true; } } diff --git a/test/service/context_menu_test.dart b/test/service/context_menu_test.dart index ace101be..e62880e9 100644 --- a/test/service/context_menu_test.dart +++ b/test/service/context_menu_test.dart @@ -16,12 +16,14 @@ void main() async { switch (message.method) { case "Clipboard.getData": return mockClipboard.getData; + case "Clipboard.setData": final args = message.arguments as Map; mockClipboard = mockClipboard.copyWith( text: args['text'], ); } + return null; }); });