Jelajahi Sumber

feat: add commands and update checkbox logic

Lucas.Xu 2 tahun lalu
induk
melakukan
6230d0ad9f

+ 62 - 0
frontend/app_flowy/packages/appflowy_editor/lib/src/commands/format_built_in_text.dart

@@ -0,0 +1,62 @@
+import 'package:appflowy_editor/src/commands/format_text.dart';
+import 'package:appflowy_editor/src/document/attributes.dart';
+import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
+import 'package:appflowy_editor/src/document/node.dart';
+import 'package:appflowy_editor/src/document/path.dart';
+import 'package:appflowy_editor/src/editor_state.dart';
+
+Future<void> formatBuiltInTextAttributes(
+  EditorState editorState,
+  String key,
+  Attributes attributes, {
+  Path? path,
+  TextNode? textNode,
+}) async {
+  if (BuiltInAttributeKey.globalStyleKeys.contains(key)) {
+    assert(!(path != null && textNode != null));
+    assert(!(path == null && textNode == null));
+
+    TextNode formattedTextNode;
+    if (textNode != null) {
+      formattedTextNode = textNode;
+    } else if (path != null) {
+      formattedTextNode = editorState.document.nodeAtPath(path) as TextNode;
+    } else {
+      throw Exception('path and textNode cannot be null at the same time');
+    }
+    // remove all the existing style
+    final newAttributes = formattedTextNode.attributes
+      ..removeWhere((key, value) {
+        if (BuiltInAttributeKey.globalStyleKeys.contains(key)) {
+          return true;
+        }
+        return false;
+      })
+      ..addAll(attributes)
+      ..addAll({
+        BuiltInAttributeKey.subtype: key,
+      });
+    return updateTextNodeAttributes(
+      editorState,
+      newAttributes,
+      textNode: textNode,
+    );
+  }
+}
+
+Future<void> formatTextToCheckbox(
+  EditorState editorState,
+  bool check, {
+  Path? path,
+  TextNode? textNode,
+}) async {
+  return formatBuiltInTextAttributes(
+    editorState,
+    BuiltInAttributeKey.checkbox,
+    {
+      BuiltInAttributeKey.checkbox: check,
+    },
+    path: path,
+    textNode: textNode,
+  );
+}

+ 34 - 0
frontend/app_flowy/packages/appflowy_editor/lib/src/commands/format_text.dart

@@ -0,0 +1,34 @@
+import 'package:appflowy_editor/src/document/attributes.dart';
+import 'package:appflowy_editor/src/document/node.dart';
+import 'package:appflowy_editor/src/document/path.dart';
+import 'package:appflowy_editor/src/editor_state.dart';
+import 'package:appflowy_editor/src/operation/transaction_builder.dart';
+import 'package:flutter/widgets.dart';
+
+Future<void> updateTextNodeAttributes(
+  EditorState editorState,
+  Attributes attributes, {
+  Path? path,
+  TextNode? textNode,
+}) async {
+  assert(!(path != null && textNode != null));
+  assert(!(path == null && textNode == null));
+
+  TextNode formattedTextNode;
+  if (textNode != null) {
+    formattedTextNode = textNode;
+  } else if (path != null) {
+    formattedTextNode = editorState.document.nodeAtPath(path) as TextNode;
+  } else {
+    throw Exception('path and textNode cannot be null at the same time');
+  }
+
+  TransactionBuilder(editorState)
+    ..updateNode(formattedTextNode, attributes)
+    ..commit();
+
+  WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+    print('AAAAAAAAAAAAAA');
+    return;
+  });
+}

+ 7 - 10
frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/checkbox_text.dart

@@ -1,15 +1,8 @@
-import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
-import 'package:appflowy_editor/src/document/node.dart';
-import 'package:appflowy_editor/src/editor_state.dart';
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:appflowy_editor/src/commands/format_built_in_text.dart';
 import 'package:appflowy_editor/src/infra/flowy_svg.dart';
 import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
-import 'package:appflowy_editor/src/render/rich_text/default_selectable.dart';
-import 'package:appflowy_editor/src/render/rich_text/flowy_rich_text.dart';
-import 'package:appflowy_editor/src/render/selection/selectable.dart';
-import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
 
-import 'package:appflowy_editor/src/service/render_plugin_service.dart';
-import 'package:appflowy_editor/src/extensions/attributes_extension.dart';
 import 'package:appflowy_editor/src/extensions/text_style_extension.dart';
 import 'package:flutter/material.dart';
 
@@ -82,7 +75,11 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
               name: check ? 'check' : 'uncheck',
             ),
             onTap: () {
-              formatCheckbox(widget.editorState, !check);
+              formatTextToCheckbox(
+                widget.editorState,
+                !check,
+                textNode: widget.textNode,
+              );
             },
           ),
           Flexible(

+ 13 - 0
frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/flowy_rich_text.dart

@@ -18,6 +18,8 @@ import 'package:appflowy_editor/src/extensions/attributes_extension.dart';
 import 'package:appflowy_editor/src/render/selection/selectable.dart';
 import 'package:appflowy_editor/src/render/toolbar/toolbar_item.dart';
 
+const _kRichTextDebugMode = false;
+
 typedef FlowyTextSpanDecorator = TextSpan Function(TextSpan textSpan);
 
 class FlowyRichText extends StatefulWidget {
@@ -261,6 +263,17 @@ class _FlowyRichTextState extends State<FlowyRichText> with SelectableMixin {
         ),
       );
     }
+    if (_kRichTextDebugMode) {
+      textSpans.add(
+        TextSpan(
+          text: '${widget.textNode.path}',
+          style: const TextStyle(
+            backgroundColor: Colors.red,
+            fontSize: 16.0,
+          ),
+        ),
+      );
+    }
     return TextSpan(
       children: textSpans,
     );

+ 8 - 4
frontend/app_flowy/packages/appflowy_editor/lib/src/service/default_text_operations/format_rich_text_style.dart

@@ -103,13 +103,17 @@ bool formatTextNodes(EditorState editorState, Attributes attributes) {
   final builder = TransactionBuilder(editorState);
 
   for (final textNode in textNodes) {
+    var newAttributes = {...textNode.attributes};
+    for (final globalStyleKey in BuiltInAttributeKey.globalStyleKeys) {
+      if (newAttributes.keys.contains(globalStyleKey)) {
+        newAttributes[globalStyleKey] = null;
+      }
+    }
+    newAttributes.addAll(attributes);
     builder
       ..updateNode(
         textNode,
-        Attributes.fromIterable(
-          BuiltInAttributeKey.globalStyleKeys,
-          value: (_) => null,
-        )..addAll(attributes),
+        newAttributes,
       )
       ..afterSelection = Selection.collapsed(
         Position(