Parcourir la source

refactor: add hitTest method for selection service

Vincent Chan il y a 2 ans
Parent
commit
b91c5d9c7b

+ 79 - 57
frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/arrow_keys_handler.dart

@@ -10,58 +10,90 @@ int _endOffsetOfNode(Node node) {
   return 0;
 }
 
-KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) {
-  final currentSelection = editorState.cursorSelection;
-  if (currentSelection == null) {
-    return KeyEventResult.ignored;
+extension on Position {
+  Position? goLeft(EditorState editorState) {
+    if (offset == 0) {
+      final node = editorState.document.nodeAtPath(path)!;
+      final prevNode = node.previous;
+      if (prevNode != null) {
+        return Position(
+            path: prevNode.path, offset: _endOffsetOfNode(prevNode));
+      }
+      return null;
+    }
+
+    return Position(path: path, offset: offset - 1);
   }
 
-  if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
-    final leftPosition = _leftPosition(editorState, currentSelection.start);
-    if (leftPosition != null) {
-      editorState.updateCursorSelection(
-          Selection(start: leftPosition, end: currentSelection.end));
-    }
-    return KeyEventResult.handled;
-  } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
-    final rightPosition = _rightPosition(editorState, currentSelection.end);
-    if (rightPosition != null) {
-      editorState.updateCursorSelection(
-          Selection(start: currentSelection.start, end: rightPosition));
+  Position? goRight(EditorState editorState) {
+    final node = editorState.document.nodeAtPath(path)!;
+    final lengthOfNode = _endOffsetOfNode(node);
+    if (offset >= lengthOfNode) {
+      final nextNode = node.next;
+      if (nextNode != null) {
+        return Position(path: nextNode.path, offset: 0);
+      }
+      return null;
     }
-    return KeyEventResult.handled;
+
+    return Position(path: path, offset: offset + 1);
   }
-  return KeyEventResult.ignored;
 }
 
-Position? _leftPosition(EditorState editorState, Position position) {
-  final offset = position.offset;
-  if (offset == 0) {
-    final node = editorState.document.nodeAtPath(position.path)!;
-    final prevNode = node.previous;
-    if (prevNode != null) {
-      editorState.updateCursorSelection(Selection.collapsed(
-          Position(path: prevNode.path, offset: _endOffsetOfNode(prevNode))));
-    }
+Position? _goUp(EditorState editorState) {
+  final rects = editorState.service.selectionService.rects();
+  if (rects.isEmpty) {
     return null;
   }
-
-  return Position(path: position.path, offset: offset - 1);
+  final first = rects.first;
+  final firstOffset = Offset(first.left, first.top);
+  final hitOffset = firstOffset - Offset(0, first.height * 0.5);
+  return editorState.service.selectionService.hitTest(hitOffset);
 }
 
-Position? _rightPosition(EditorState editorState, Position position) {
-  final offset = position.offset;
-  final node = editorState.document.nodeAtPath(position.path)!;
-  final lengthOfNode = _endOffsetOfNode(node);
-  if (offset >= lengthOfNode) {
-    final nextNode = node.next;
-    if (nextNode != null) {
-      Position(path: nextNode.path, offset: 0);
-    }
+Position? _goDown(EditorState editorState) {
+  final rects = editorState.service.selectionService.rects();
+  if (rects.isEmpty) {
     return null;
   }
+  final first = rects.last;
+  final firstOffset = Offset(first.right, first.bottom);
+  final hitOffset = firstOffset + Offset(0, first.height * 0.5);
+  return editorState.service.selectionService.hitTest(hitOffset);
+}
 
-  return Position(path: position.path, offset: offset + 1);
+KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) {
+  final currentSelection = editorState.cursorSelection;
+  if (currentSelection == null) {
+    return KeyEventResult.ignored;
+  }
+
+  if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
+    final leftPosition = currentSelection.end.goLeft(editorState);
+    editorState.updateCursorSelection(leftPosition == null
+        ? null
+        : Selection(start: currentSelection.start, end: leftPosition));
+    return KeyEventResult.handled;
+  } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
+    final rightPosition = currentSelection.start.goRight(editorState);
+    editorState.updateCursorSelection(rightPosition == null
+        ? null
+        : Selection(start: rightPosition, end: currentSelection.end));
+    return KeyEventResult.handled;
+  } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
+    final position = _goUp(editorState);
+    editorState.updateCursorSelection(position == null
+        ? null
+        : Selection(start: position, end: currentSelection.end));
+    return KeyEventResult.handled;
+  } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
+    final position = _goDown(editorState);
+    editorState.updateCursorSelection(position == null
+        ? null
+        : Selection(start: currentSelection.start, end: position));
+    return KeyEventResult.handled;
+  }
+  return KeyEventResult.ignored;
 }
 
 FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
@@ -76,7 +108,7 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
 
   if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
     if (currentSelection.isCollapsed) {
-      final leftPosition = _leftPosition(editorState, currentSelection.start);
+      final leftPosition = currentSelection.start.goLeft(editorState);
       if (leftPosition != null) {
         editorState.updateCursorSelection(Selection.collapsed(leftPosition));
       }
@@ -87,7 +119,7 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
     return KeyEventResult.handled;
   } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
     if (currentSelection.isCollapsed) {
-      final rightPosition = _rightPosition(editorState, currentSelection.end);
+      final rightPosition = currentSelection.end.goRight(editorState);
       if (rightPosition != null) {
         editorState.updateCursorSelection(Selection.collapsed(rightPosition));
       }
@@ -96,24 +128,14 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
     }
     return KeyEventResult.handled;
   } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
-    final rects = editorState.service.selectionService.rects();
-    if (rects.isEmpty) {
-      return KeyEventResult.handled;
-    }
-    final first = rects.first;
-    final firstOffset = Offset(first.left, first.top);
-    final hitOffset = firstOffset - Offset(0, first.height * 0.5);
-    editorState.service.selectionService.hit(hitOffset);
+    final position = _goUp(editorState);
+    editorState.updateCursorSelection(
+        position == null ? null : Selection.collapsed(position));
     return KeyEventResult.handled;
   } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
-    final rects = editorState.service.selectionService.rects();
-    if (rects.isEmpty) {
-      return KeyEventResult.handled;
-    }
-    final first = rects.last;
-    final firstOffset = Offset(first.right, first.bottom);
-    final hitOffset = firstOffset + Offset(0, first.height * 0.5);
-    editorState.service.selectionService.hit(hitOffset);
+    final position = _goDown(editorState);
+    editorState.updateCursorSelection(
+        position == null ? null : Selection.collapsed(position));
     return KeyEventResult.handled;
   }
 

+ 12 - 9
frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart

@@ -30,7 +30,7 @@ mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
 
   List<Rect> rects();
 
-  hit(Offset? offset);
+  Position? hitTest(Offset? offset);
 
   ///
   List<Node> getNodesInSelection(Selection selection);
@@ -285,29 +285,32 @@ class _FlowySelectionState extends State<FlowySelection>
 
     tapOffset = details.globalPosition;
 
-    hit(tapOffset);
+    final position = hitTest(tapOffset);
+    if (position == null) {
+      return;
+    }
+    final selection = Selection.collapsed(position);
+    editorState.updateCursorSelection(selection);
   }
 
   @override
-  hit(Offset? offset) {
+  Position? hitTest(Offset? offset) {
     if (offset == null) {
       editorState.updateCursorSelection(null);
-      return;
+      return null;
     }
     final nodes = getNodesInRange(offset);
     if (nodes.isEmpty) {
       editorState.updateCursorSelection(null);
-      return;
+      return null;
     }
     assert(nodes.length == 1);
     final selectable = nodes.first.selectable;
     if (selectable == null) {
       editorState.updateCursorSelection(null);
-      return;
+      return null;
     }
-    final position = selectable.getPositionInOffset(offset);
-    final selection = Selection.collapsed(position);
-    editorState.updateCursorSelection(selection);
+    return selectable.getPositionInOffset(offset);
   }
 
   void _onPanStart(DragStartDetails details) {