mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: handle arrow keys
This commit is contained in:
parent
982cd62fcc
commit
e74f5e84dc
@ -126,7 +126,7 @@ class __TextNodeWidgetState extends State<_TextNodeWidget>
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
),
|
||||
);
|
||||
editorState.cursorSelection = _localSelectionToGlobal(node, selection);
|
||||
editorState.updateCursorSelection(_localSelectionToGlobal(node, selection));
|
||||
_textInputConnection
|
||||
?..show()
|
||||
..setEditingState(
|
||||
|
@ -31,7 +31,22 @@ class EditorState {
|
||||
final service = FlowyService();
|
||||
|
||||
final UndoManager undoManager = UndoManager();
|
||||
Selection? cursorSelection;
|
||||
Selection? _cursorSelection;
|
||||
|
||||
Selection? get cursorSelection {
|
||||
return _cursorSelection;
|
||||
}
|
||||
|
||||
/// add the set reason in the future, don't use setter
|
||||
updateCursorSelection(Selection? cursorSelection) {
|
||||
// broadcast to other users here
|
||||
if (cursorSelection == null) {
|
||||
service.selectionService.clearSelection();
|
||||
} else {
|
||||
service.selectionService.updateSelection(cursorSelection);
|
||||
}
|
||||
_cursorSelection = cursorSelection;
|
||||
}
|
||||
|
||||
Timer? _debouncedSealHistoryItemTimer;
|
||||
|
||||
@ -58,7 +73,7 @@ class EditorState {
|
||||
for (final op in transaction.operations) {
|
||||
_applyOperation(op);
|
||||
}
|
||||
cursorSelection = transaction.afterSelection;
|
||||
updateCursorSelection(transaction.afterSelection);
|
||||
|
||||
if (options.recordUndo) {
|
||||
final undoItem = undoManager.getUndoHistoryItem();
|
||||
|
@ -1,7 +1,17 @@
|
||||
import 'package:flowy_editor/document/node.dart';
|
||||
import 'package:flowy_editor/document/position.dart';
|
||||
import 'package:flowy_editor/service/keyboard_service.dart';
|
||||
import 'package:flowy_editor/document/selection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
int _endOffsetOfNode(Node node) {
|
||||
if (node is TextNode) {
|
||||
return node.delta.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
||||
if (event.logicalKey != LogicalKeyboardKey.arrowUp &&
|
||||
event.logicalKey != LogicalKeyboardKey.arrowDown &&
|
||||
@ -10,5 +20,54 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
final currentSelection = editorState.cursorSelection;
|
||||
if (currentSelection == null) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
||||
// turn left
|
||||
if (currentSelection.isCollapsed) {
|
||||
final end = currentSelection.end;
|
||||
final offset = end.offset;
|
||||
if (offset == 0) {
|
||||
final node = editorState.document.nodeAtPath(end.path)!;
|
||||
final prevNode = node.previous;
|
||||
if (prevNode != null) {
|
||||
editorState.updateCursorSelection(Selection.collapsed(Position(
|
||||
path: prevNode.path, offset: _endOffsetOfNode(prevNode))));
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
editorState.updateCursorSelection(
|
||||
Selection.collapsed(Position(path: end.path, offset: offset - 1)));
|
||||
} else {
|
||||
editorState
|
||||
.updateCursorSelection(currentSelection.collapse(atStart: true));
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
||||
if (currentSelection.isCollapsed) {
|
||||
final end = currentSelection.end;
|
||||
final offset = end.offset;
|
||||
final node = editorState.document.nodeAtPath(end.path)!;
|
||||
final lengthOfNode = _endOffsetOfNode(node);
|
||||
if (offset >= lengthOfNode) {
|
||||
final nextNode = node.next;
|
||||
if (nextNode != null) {
|
||||
editorState.updateCursorSelection(
|
||||
Selection.collapsed(Position(path: nextNode.path, offset: 0)));
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
editorState.updateCursorSelection(
|
||||
Selection.collapsed(Position(path: end.path, offset: offset + 1)));
|
||||
} else {
|
||||
editorState.updateCursorSelection(currentSelection.collapse());
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
return KeyEventResult.ignored;
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'package:flowy_editor/document/path.dart';
|
||||
import 'package:flowy_editor/document/node.dart';
|
||||
import 'package:flowy_editor/document/position.dart';
|
||||
import 'package:flowy_editor/document/selection.dart';
|
||||
@ -49,7 +48,7 @@ mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
Node? computeNodeInOffset(Node node, Offset offset);
|
||||
|
||||
/// Return the [Node]s in multiple selection. Emtpy list would be returned
|
||||
/// Return the [Node]s in multiple selection. Empty list would be returned
|
||||
/// if no nodes are in range.
|
||||
///
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
@ -136,8 +135,8 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
TapGestureRecognizer:
|
||||
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
|
||||
() => TapGestureRecognizer(),
|
||||
(recongizer) {
|
||||
recongizer.onTapDown = _onTapDown;
|
||||
(recognizer) {
|
||||
recognizer.onTapDown = _onTapDown;
|
||||
},
|
||||
)
|
||||
},
|
||||
@ -167,9 +166,9 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
if (end != null) {
|
||||
return computeNodesInRange(editorState.document.root, start, end);
|
||||
} else {
|
||||
final reuslt = computeNodeInOffset(editorState.document.root, start);
|
||||
if (reuslt != null) {
|
||||
return [reuslt];
|
||||
final result = computeNodeInOffset(editorState.document.root, start);
|
||||
if (result != null) {
|
||||
return [result];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
@ -253,8 +252,10 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
if (selectable != null) {
|
||||
final position = selectable.getPositionInOffset(tapOffset!);
|
||||
final selection = Selection.collapsed(position);
|
||||
updateSelection(selection);
|
||||
editorState.updateCursorSelection(selection);
|
||||
}
|
||||
} else {
|
||||
editorState.updateCursorSelection(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,7 +284,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
final selection = Selection(
|
||||
start: isDownward ? start : end, end: isDownward ? end : start);
|
||||
debugPrint('[_onPanUpdate] $selection');
|
||||
updateSelection(selection);
|
||||
editorState.updateCursorSelection(selection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,7 +303,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
_cursorOverlays
|
||||
..forEach((overlay) => overlay.remove())
|
||||
..clear();
|
||||
// clear floating shortcusts
|
||||
// clear floating shortcuts
|
||||
editorState.service.floatingShortcutServiceKey.currentState
|
||||
?.unwrapOrNull<FlowyFloatingShortcutService>()
|
||||
?.hide();
|
||||
|
Loading…
Reference in New Issue
Block a user