feat: Implement arrow up/down/left/right event handler. #708

This commit is contained in:
Lucas.Xu 2022-07-25 15:58:57 +08:00
parent e1d990e4ae
commit 2f86cac8af
9 changed files with 110 additions and 9 deletions

View File

@ -61,6 +61,16 @@ class __ImageNodeWidgetState extends State<_ImageNodeWidget> with Selectable {
return Offset.zero;
}
@override
Offset getLeftOfOffset() {
return Offset.zero;
}
@override
Offset getRightOfOffset() {
return Offset.zero;
}
@override
Widget build(BuildContext context) {
return _build(context);

View File

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:example/plugin/debuggable_rich_text.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/foundation.dart';
@ -108,6 +110,30 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget>
return _renderParagraph.localToGlobal(offset);
}
@override
Offset getLeftOfOffset() {
final textSelection = _textSelection;
if (textSelection != null) {
final leftTextSelection = TextSelection.collapsed(
offset: max(0, textSelection.baseOffset - 1),
);
return getOffsetByTextSelection(leftTextSelection);
}
return Offset.zero;
}
@override
Offset getRightOfOffset() {
final textSelection = _textSelection;
if (textSelection != null) {
final leftTextSelection = TextSelection.collapsed(
offset: min(node.toRawString().length, textSelection.extentOffset + 1),
);
return getOffsetByTextSelection(leftTextSelection);
}
return Offset.zero;
}
@override
Widget build(BuildContext context) {
Widget richText;
@ -117,6 +143,10 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget>
richText = RichText(key: _textKey, text: node.toTextSpan());
}
if (node.children.isEmpty) {
return richText;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flowy_editor/service/service.dart';
import 'package:flutter/material.dart';
import 'package:flowy_editor/document/node.dart';
@ -19,13 +20,14 @@ class ApplyOptions {
});
}
// TODO
final selectionServiceKey = GlobalKey();
class EditorState {
final StateTree document;
final RenderPlugins renderPlugins;
List<Node> selectedNodes = [];
// Service reference.
final service = FlowyService();
final UndoManager undoManager = UndoManager();
Selection? cursorSelection;

View File

@ -11,6 +11,12 @@ mixin Selectable<T extends StatefulWidget> on State<T> {
/// The return result must be an local offset.
Rect getCursorRect(Offset start);
/// Returns one unit offset to the left of the offset
Offset getLeftOfOffset(/* Cause */);
/// Returns one unit offset to the right of the offset
Offset getRightOfOffset(/* Cause */);
/// For [TextNode] only.
TextSelection? getTextSelection();

View File

@ -1,3 +1,4 @@
import 'package:flowy_editor/service/flowy_key_event_handlers/arrow_keys_handler.dart';
import 'package:flowy_editor/service/flowy_key_event_handlers/delete_nodes_handler.dart';
import 'package:flowy_editor/service/flowy_key_event_handlers/delete_single_text_node_handler.dart';
import 'package:flowy_editor/service/keyboard_service.dart';
@ -26,12 +27,14 @@ class _FlowyEditorState extends State<FlowyEditor> {
@override
Widget build(BuildContext context) {
return FlowySelection(
key: selectionServiceKey,
key: editorState.service.selectionServiceKey,
editorState: editorState,
child: FlowyKeyboard(
key: editorState.service.keyboardServiceKey,
handlers: [
flowyDeleteNodesHandler,
deleteSingleTextNodeHandler,
arrowKeysHandler,
...widget.keyEventHandler,
],
editorState: editorState,

View File

@ -0,0 +1,37 @@
import 'package:flowy_editor/extensions/object_extensions.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_editor/service/keyboard_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
if (event.logicalKey != LogicalKeyboardKey.arrowUp &&
event.logicalKey != LogicalKeyboardKey.arrowDown &&
event.logicalKey != LogicalKeyboardKey.arrowLeft &&
event.logicalKey != LogicalKeyboardKey.arrowRight) {
return KeyEventResult.ignored;
}
// TODO: Up and Down
// Left and Right
final selectedNodes = editorState.selectedNodes;
if (selectedNodes.length != 1) {
return KeyEventResult.ignored;
}
final node = selectedNodes.first.unwrapOrNull<TextNode>();
final selectable = node?.key?.currentState?.unwrapOrNull<Selectable>();
Offset? offset;
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
offset = selectable?.getLeftOfOffset();
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
offset = selectable?.getRightOfOffset();
}
final selectionService = editorState.service.selectionService;
if (offset != null) {
selectionService.updateCursor(offset);
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
};

View File

@ -33,8 +33,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) {
final previous = node!.previous! as TextNode;
final newTextSelection = TextSelection.collapsed(
offset: previous.toRawString().length);
final selectionService =
selectionServiceKey.currentState as FlowySelectionService;
final selectionService = editorState.service.selectionService;
final previousSelectable =
previous.key?.currentState?.unwrapOrNull<Selectable>();
final newOfset = previousSelectable
@ -58,8 +57,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) {
..commit();
final newTextSelection =
TextSelection.collapsed(offset: textSelection.baseOffset - 1);
final selectionService =
selectionServiceKey.currentState as FlowySelectionService;
final selectionService = editorState.service.selectionService;
final newOfset =
selectable.getOffsetByTextSelection(newTextSelection);
selectionService.updateCursor(newOfset);

View File

@ -46,7 +46,7 @@ class _FlowyKeyboardState extends State<FlowyKeyboard> {
}
for (final handler in widget.handlers) {
debugPrint('handle keyboard event $event by $handler');
// debugPrint('handle keyboard event $event by $handler');
KeyEventResult result = handler(widget.editorState, event);

View File

@ -0,0 +1,15 @@
import 'package:flowy_editor/service/selection_service.dart';
import 'package:flutter/material.dart';
class FlowyService {
// selection service
final selectionServiceKey = GlobalKey(debugLabel: 'flowy_selection_service');
FlowySelectionService get selectionService {
assert(selectionServiceKey.currentState != null &&
selectionServiceKey.currentState is FlowySelectionService);
return selectionServiceKey.currentState! as FlowySelectionService;
}
// keyboard service
final keyboardServiceKey = GlobalKey(debugLabel: 'flowy_keyboard_service');
}