Sfoglia il codice sorgente

Merge pull request #1209 from alemoreau/double_tilde_to_strikethrough

feat: double tildes to strikethrough text
Lucas.Xu 2 anni fa
parent
commit
e67f91b380

+ 16 - 16
frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_fr-CA.dart

@@ -22,21 +22,21 @@ class MessageLookup extends MessageLookupByLibrary {
 
   final messages = _notInlinedMessages(_notInlinedMessages);
   static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
-        "bold": MessageLookupByLibrary.simpleMessage(""),
-        "bulletedList": MessageLookupByLibrary.simpleMessage(""),
-        "checkbox": MessageLookupByLibrary.simpleMessage(""),
-        "embedCode": MessageLookupByLibrary.simpleMessage(""),
-        "heading1": MessageLookupByLibrary.simpleMessage(""),
-        "heading2": MessageLookupByLibrary.simpleMessage(""),
-        "heading3": MessageLookupByLibrary.simpleMessage(""),
-        "highlight": MessageLookupByLibrary.simpleMessage(""),
-        "image": MessageLookupByLibrary.simpleMessage(""),
-        "italic": MessageLookupByLibrary.simpleMessage(""),
-        "link": MessageLookupByLibrary.simpleMessage(""),
-        "numberedList": MessageLookupByLibrary.simpleMessage(""),
-        "quote": MessageLookupByLibrary.simpleMessage(""),
-        "strikethrough": MessageLookupByLibrary.simpleMessage(""),
-        "text": MessageLookupByLibrary.simpleMessage(""),
-        "underline": MessageLookupByLibrary.simpleMessage("")
+        "bold": MessageLookupByLibrary.simpleMessage("gras"),
+        "bulletedList": MessageLookupByLibrary.simpleMessage("liste à puces"),
+        "checkbox": MessageLookupByLibrary.simpleMessage("case à cocher"),
+        "embedCode": MessageLookupByLibrary.simpleMessage("incorporer Code"),
+        "heading1": MessageLookupByLibrary.simpleMessage("en-tête1"),
+        "heading2": MessageLookupByLibrary.simpleMessage("en-tête2"),
+        "heading3": MessageLookupByLibrary.simpleMessage("en-tête3"),
+        "highlight": MessageLookupByLibrary.simpleMessage("mettre en évidence"),
+        "image": MessageLookupByLibrary.simpleMessage("l’image"),
+        "italic": MessageLookupByLibrary.simpleMessage("italique"),
+        "link": MessageLookupByLibrary.simpleMessage("lien"),
+        "numberedList": MessageLookupByLibrary.simpleMessage("liste numérotée"),
+        "quote": MessageLookupByLibrary.simpleMessage("citation"),
+        "strikethrough": MessageLookupByLibrary.simpleMessage("barré"),
+        "text": MessageLookupByLibrary.simpleMessage("texte"),
+        "underline": MessageLookupByLibrary.simpleMessage("souligner")
       };
 }

+ 16 - 16
frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_hu-HU.dart

@@ -22,21 +22,21 @@ class MessageLookup extends MessageLookupByLibrary {
 
   final messages = _notInlinedMessages(_notInlinedMessages);
   static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
-        "bold": MessageLookupByLibrary.simpleMessage(""),
-        "bulletedList": MessageLookupByLibrary.simpleMessage(""),
-        "checkbox": MessageLookupByLibrary.simpleMessage(""),
-        "embedCode": MessageLookupByLibrary.simpleMessage(""),
-        "heading1": MessageLookupByLibrary.simpleMessage(""),
-        "heading2": MessageLookupByLibrary.simpleMessage(""),
-        "heading3": MessageLookupByLibrary.simpleMessage(""),
-        "highlight": MessageLookupByLibrary.simpleMessage(""),
-        "image": MessageLookupByLibrary.simpleMessage(""),
-        "italic": MessageLookupByLibrary.simpleMessage(""),
-        "link": MessageLookupByLibrary.simpleMessage(""),
-        "numberedList": MessageLookupByLibrary.simpleMessage(""),
-        "quote": MessageLookupByLibrary.simpleMessage(""),
-        "strikethrough": MessageLookupByLibrary.simpleMessage(""),
-        "text": MessageLookupByLibrary.simpleMessage(""),
-        "underline": MessageLookupByLibrary.simpleMessage("")
+        "bold": MessageLookupByLibrary.simpleMessage("bátor"),
+        "bulletedList": MessageLookupByLibrary.simpleMessage("pontozott lista"),
+        "checkbox": MessageLookupByLibrary.simpleMessage("jelölőnégyzetet"),
+        "embedCode": MessageLookupByLibrary.simpleMessage("Beágyazás"),
+        "heading1": MessageLookupByLibrary.simpleMessage("címsor1"),
+        "heading2": MessageLookupByLibrary.simpleMessage("címsor2"),
+        "heading3": MessageLookupByLibrary.simpleMessage("címsor3"),
+        "highlight": MessageLookupByLibrary.simpleMessage("Kiemel"),
+        "image": MessageLookupByLibrary.simpleMessage("kép"),
+        "italic": MessageLookupByLibrary.simpleMessage("dőlt"),
+        "link": MessageLookupByLibrary.simpleMessage("link"),
+        "numberedList": MessageLookupByLibrary.simpleMessage("számozottLista"),
+        "quote": MessageLookupByLibrary.simpleMessage("idézet"),
+        "strikethrough": MessageLookupByLibrary.simpleMessage("áthúzott"),
+        "text": MessageLookupByLibrary.simpleMessage("szöveg"),
+        "underline": MessageLookupByLibrary.simpleMessage("aláhúzás")
       };
 }

+ 16 - 16
frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_id-ID.dart

@@ -22,21 +22,21 @@ class MessageLookup extends MessageLookupByLibrary {
 
   final messages = _notInlinedMessages(_notInlinedMessages);
   static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
-        "bold": MessageLookupByLibrary.simpleMessage(""),
-        "bulletedList": MessageLookupByLibrary.simpleMessage(""),
-        "checkbox": MessageLookupByLibrary.simpleMessage(""),
-        "embedCode": MessageLookupByLibrary.simpleMessage(""),
-        "heading1": MessageLookupByLibrary.simpleMessage(""),
-        "heading2": MessageLookupByLibrary.simpleMessage(""),
-        "heading3": MessageLookupByLibrary.simpleMessage(""),
-        "highlight": MessageLookupByLibrary.simpleMessage(""),
-        "image": MessageLookupByLibrary.simpleMessage(""),
-        "italic": MessageLookupByLibrary.simpleMessage(""),
-        "link": MessageLookupByLibrary.simpleMessage(""),
-        "numberedList": MessageLookupByLibrary.simpleMessage(""),
-        "quote": MessageLookupByLibrary.simpleMessage(""),
-        "strikethrough": MessageLookupByLibrary.simpleMessage(""),
-        "text": MessageLookupByLibrary.simpleMessage(""),
-        "underline": MessageLookupByLibrary.simpleMessage("")
+        "bold": MessageLookupByLibrary.simpleMessage("berani"),
+        "bulletedList": MessageLookupByLibrary.simpleMessage("daftar berpoin"),
+        "checkbox": MessageLookupByLibrary.simpleMessage("kotak centang"),
+        "embedCode": MessageLookupByLibrary.simpleMessage("menyematkan Kode"),
+        "heading1": MessageLookupByLibrary.simpleMessage("pos1"),
+        "heading2": MessageLookupByLibrary.simpleMessage("pos2"),
+        "heading3": MessageLookupByLibrary.simpleMessage("pos3"),
+        "highlight": MessageLookupByLibrary.simpleMessage("menyorot"),
+        "image": MessageLookupByLibrary.simpleMessage("gambar"),
+        "italic": MessageLookupByLibrary.simpleMessage("miring"),
+        "link": MessageLookupByLibrary.simpleMessage("tautan"),
+        "numberedList": MessageLookupByLibrary.simpleMessage("daftar bernomor"),
+        "quote": MessageLookupByLibrary.simpleMessage("mengutip"),
+        "strikethrough": MessageLookupByLibrary.simpleMessage("coret"),
+        "text": MessageLookupByLibrary.simpleMessage("teks"),
+        "underline": MessageLookupByLibrary.simpleMessage("menggarisbawahi")
       };
 }

+ 17 - 16
frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_pt-PT.dart

@@ -22,21 +22,22 @@ class MessageLookup extends MessageLookupByLibrary {
 
   final messages = _notInlinedMessages(_notInlinedMessages);
   static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
-        "bold": MessageLookupByLibrary.simpleMessage(""),
-        "bulletedList": MessageLookupByLibrary.simpleMessage(""),
-        "checkbox": MessageLookupByLibrary.simpleMessage(""),
-        "embedCode": MessageLookupByLibrary.simpleMessage(""),
-        "heading1": MessageLookupByLibrary.simpleMessage(""),
-        "heading2": MessageLookupByLibrary.simpleMessage(""),
-        "heading3": MessageLookupByLibrary.simpleMessage(""),
-        "highlight": MessageLookupByLibrary.simpleMessage(""),
-        "image": MessageLookupByLibrary.simpleMessage(""),
-        "italic": MessageLookupByLibrary.simpleMessage(""),
-        "link": MessageLookupByLibrary.simpleMessage(""),
-        "numberedList": MessageLookupByLibrary.simpleMessage(""),
-        "quote": MessageLookupByLibrary.simpleMessage(""),
-        "strikethrough": MessageLookupByLibrary.simpleMessage(""),
-        "text": MessageLookupByLibrary.simpleMessage(""),
-        "underline": MessageLookupByLibrary.simpleMessage("")
+        "bold": MessageLookupByLibrary.simpleMessage("negrito"),
+        "bulletedList":
+            MessageLookupByLibrary.simpleMessage("lista com marcadores"),
+        "checkbox": MessageLookupByLibrary.simpleMessage("caixa de seleção"),
+        "embedCode": MessageLookupByLibrary.simpleMessage("Código embutido"),
+        "heading1": MessageLookupByLibrary.simpleMessage("Cabeçallho 1"),
+        "heading2": MessageLookupByLibrary.simpleMessage("Cabeçallho 2"),
+        "heading3": MessageLookupByLibrary.simpleMessage("Cabeçallho 3"),
+        "highlight": MessageLookupByLibrary.simpleMessage("realçar"),
+        "image": MessageLookupByLibrary.simpleMessage("imagem"),
+        "italic": MessageLookupByLibrary.simpleMessage("itálico"),
+        "link": MessageLookupByLibrary.simpleMessage("link"),
+        "numberedList": MessageLookupByLibrary.simpleMessage("lista numerada"),
+        "quote": MessageLookupByLibrary.simpleMessage("citar"),
+        "strikethrough": MessageLookupByLibrary.simpleMessage("tachado"),
+        "text": MessageLookupByLibrary.simpleMessage("texto"),
+        "underline": MessageLookupByLibrary.simpleMessage("sublinhado")
       };
 }

+ 64 - 2
frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart

@@ -1,4 +1,3 @@
-import "dart:math";
 import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
 import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
@@ -49,7 +48,7 @@ ShortcutEventHandler backquoteToCodeHandler = (editorState, event) {
       .substring(selection.start.offset, selection.end.offset);
 
   // toggle code style when selected some text
-  if (selectionText.length > 0) {
+  if (selectionText.isNotEmpty) {
     formatEmbedCode(editorState);
     return KeyEventResult.handled;
   }
@@ -125,6 +124,69 @@ ShortcutEventHandler backquoteToCodeHandler = (editorState, event) {
   return KeyEventResult.handled;
 };
 
+// convert ~~abc~~ to strikethrough abc.
+ShortcutEventHandler doubleTildeToStrikethrough = (editorState, event) {
+  final selectionService = editorState.service.selectionService;
+  final selection = selectionService.currentSelection.value;
+  final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
+  if (selection == null || !selection.isSingle || textNodes.length != 1) {
+    return KeyEventResult.ignored;
+  }
+
+  final textNode = textNodes.first;
+  final text = textNode.toRawString().substring(0, selection.end.offset);
+
+  // make sure the last two characters are ~~.
+  if (text.length < 2 || text[selection.end.offset - 1] != '~') {
+    return KeyEventResult.ignored;
+  }
+
+  // find all the index of `~`.
+  final tildeIndexes = <int>[];
+  for (var i = 0; i < text.length; i++) {
+    if (text[i] == '~') {
+      tildeIndexes.add(i);
+    }
+  }
+
+  if (tildeIndexes.length < 3) {
+    return KeyEventResult.ignored;
+  }
+
+  // make sure the second to last and third to last tildes are connected.
+  final thirdToLastTildeIndex = tildeIndexes[tildeIndexes.length - 3];
+  final secondToLastTildeIndex = tildeIndexes[tildeIndexes.length - 2];
+  final lastTildeIndex = tildeIndexes[tildeIndexes.length - 1];
+  if (secondToLastTildeIndex != thirdToLastTildeIndex + 1 ||
+      lastTildeIndex == secondToLastTildeIndex + 1) {
+    return KeyEventResult.ignored;
+  }
+
+  // delete the last three tildes.
+  // update the style of the text surround by `~~ ~~` to strikethrough.
+  // and update the cursor position.
+  TransactionBuilder(editorState)
+    ..deleteText(textNode, lastTildeIndex, 1)
+    ..deleteText(textNode, thirdToLastTildeIndex, 2)
+    ..formatText(
+      textNode,
+      thirdToLastTildeIndex,
+      selection.end.offset - thirdToLastTildeIndex - 2,
+      {
+        BuiltInAttributeKey.strikethrough: true,
+      },
+    )
+    ..afterSelection = Selection.collapsed(
+      Position(
+        path: textNode.path,
+        offset: selection.end.offset - 3,
+      ),
+    )
+    ..commit();
+
+  return KeyEventResult.handled;
+};
+
 /// To create a link, enclose the link text in brackets (e.g., [link text]).
 /// Then, immediately follow it with the URL in parentheses (e.g., (https://example.com)).
 ShortcutEventHandler markdownLinkToLinkHandler = (editorState, event) {

+ 5 - 0
frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart

@@ -257,6 +257,11 @@ List<ShortcutEvent> builtInShortcutEvents = [
     command: 'backquote',
     handler: backquoteToCodeHandler,
   ),
+  ShortcutEvent(
+    key: 'Double tilde to strikethrough',
+    command: 'shift+tilde',
+    handler: doubleTildeToStrikethrough,
+  ),
   ShortcutEvent(
     key: 'Markdown link to link',
     command: 'shift+parenthesis right',

+ 3 - 0
frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart

@@ -139,6 +139,9 @@ extension on LogicalKeyboardKey {
     if (this == LogicalKeyboardKey.keyZ) {
       return PhysicalKeyboardKey.keyZ;
     }
+    if (this == LogicalKeyboardKey.tilde) {
+      return PhysicalKeyboardKey.backquote;
+    }
     throw UnimplementedError();
   }
 }

+ 106 - 0
frontend/app_flowy/packages/appflowy_editor/test/service/internal_key_event_handlers/markdown_syntax_to_styled_text_test.dart

@@ -150,5 +150,111 @@ void main() async {
         expect(textNode.toRawString(), text);
       });
     });
+
+    group('convert double tilde to strikethrough', () {
+      Future<void> insertTilde(
+        EditorWidgetTester editor, {
+        int repeat = 1,
+      }) async {
+        for (var i = 0; i < repeat; i++) {
+          await editor.pressLogicKey(
+            LogicalKeyboardKey.tilde,
+            isShiftPressed: true,
+          );
+        }
+      }
+
+      testWidgets('~~AppFlowy~~ to strikethrough AppFlowy', (tester) async {
+        const text = '~~AppFlowy~';
+        final editor = tester.editor..insertTextNode('');
+        await editor.startTesting();
+        await editor.updateSelection(
+          Selection.single(path: [0], startOffset: 0),
+        );
+        final textNode = editor.nodeAtPath([0]) as TextNode;
+        for (var i = 0; i < text.length; i++) {
+          await editor.insertText(textNode, text[i], i);
+        }
+        await insertTilde(editor);
+        final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
+          Selection.single(
+            path: [0],
+            startOffset: 0,
+            endOffset: textNode.toRawString().length,
+          ),
+        );
+        expect(allStrikethrough, true);
+        expect(textNode.toRawString(), 'AppFlowy');
+      });
+
+      testWidgets('App~~Flowy~~ to strikethrough AppFlowy', (tester) async {
+        const text = 'App~~Flowy~';
+        final editor = tester.editor..insertTextNode('');
+        await editor.startTesting();
+        await editor.updateSelection(
+          Selection.single(path: [0], startOffset: 0),
+        );
+        final textNode = editor.nodeAtPath([0]) as TextNode;
+        for (var i = 0; i < text.length; i++) {
+          await editor.insertText(textNode, text[i], i);
+        }
+        await insertTilde(editor);
+        final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
+          Selection.single(
+            path: [0],
+            startOffset: 3,
+            endOffset: textNode.toRawString().length,
+          ),
+        );
+        expect(allStrikethrough, true);
+        expect(textNode.toRawString(), 'AppFlowy');
+      });
+
+      testWidgets('~~~AppFlowy~~ to bold ~AppFlowy', (tester) async {
+        const text = '~~~AppFlowy~';
+        final editor = tester.editor..insertTextNode('');
+        await editor.startTesting();
+        await editor.updateSelection(
+          Selection.single(path: [0], startOffset: 0),
+        );
+        final textNode = editor.nodeAtPath([0]) as TextNode;
+        for (var i = 0; i < text.length; i++) {
+          await editor.insertText(textNode, text[i], i);
+        }
+        await insertTilde(editor);
+        final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
+          Selection.single(
+            path: [0],
+            startOffset: 1,
+            endOffset: textNode.toRawString().length,
+          ),
+        );
+        expect(allStrikethrough, true);
+        expect(textNode.toRawString(), '~AppFlowy');
+      });
+
+      testWidgets('~~~~ nothing changes', (tester) async {
+        const text = '~~~';
+        final editor = tester.editor..insertTextNode('');
+        await editor.startTesting();
+        await editor.updateSelection(
+          Selection.single(path: [0], startOffset: 0),
+        );
+        final textNode = editor.nodeAtPath([0]) as TextNode;
+        for (var i = 0; i < text.length; i++) {
+          await editor.insertText(textNode, text[i], i);
+        }
+        await insertTilde(editor);
+        final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
+          Selection.single(
+            path: [0],
+            startOffset: 0,
+            endOffset: textNode.toRawString().length,
+          ),
+        );
+        expect(allStrikethrough, false);
+        expect(textNode.toRawString(), text);
+      });
+    });
   });
 }