mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: Implement arrow up/down/left/right event handler. #708
This commit is contained in:
parent
e1d990e4ae
commit
2f86cac8af
@ -61,6 +61,16 @@ class __ImageNodeWidgetState extends State<_ImageNodeWidget> with Selectable {
|
|||||||
return Offset.zero;
|
return Offset.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Offset getLeftOfOffset() {
|
||||||
|
return Offset.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Offset getRightOfOffset() {
|
||||||
|
return Offset.zero;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _build(context);
|
return _build(context);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:example/plugin/debuggable_rich_text.dart';
|
import 'package:example/plugin/debuggable_rich_text.dart';
|
||||||
import 'package:flowy_editor/flowy_editor.dart';
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -108,6 +110,30 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget>
|
|||||||
return _renderParagraph.localToGlobal(offset);
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget richText;
|
Widget richText;
|
||||||
@ -117,6 +143,10 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget>
|
|||||||
richText = RichText(key: _textKey, text: node.toTextSpan());
|
richText = RichText(key: _textKey, text: node.toTextSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.children.isEmpty) {
|
||||||
|
return richText;
|
||||||
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:flowy_editor/service/service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flowy_editor/document/node.dart';
|
import 'package:flowy_editor/document/node.dart';
|
||||||
@ -19,13 +20,14 @@ class ApplyOptions {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
final selectionServiceKey = GlobalKey();
|
|
||||||
|
|
||||||
class EditorState {
|
class EditorState {
|
||||||
final StateTree document;
|
final StateTree document;
|
||||||
final RenderPlugins renderPlugins;
|
final RenderPlugins renderPlugins;
|
||||||
List<Node> selectedNodes = [];
|
List<Node> selectedNodes = [];
|
||||||
|
|
||||||
|
// Service reference.
|
||||||
|
final service = FlowyService();
|
||||||
|
|
||||||
final UndoManager undoManager = UndoManager();
|
final UndoManager undoManager = UndoManager();
|
||||||
Selection? cursorSelection;
|
Selection? cursorSelection;
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@ mixin Selectable<T extends StatefulWidget> on State<T> {
|
|||||||
/// The return result must be an local offset.
|
/// The return result must be an local offset.
|
||||||
Rect getCursorRect(Offset start);
|
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.
|
/// For [TextNode] only.
|
||||||
TextSelection? getTextSelection();
|
TextSelection? getTextSelection();
|
||||||
|
|
||||||
|
@ -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_nodes_handler.dart';
|
||||||
import 'package:flowy_editor/service/flowy_key_event_handlers/delete_single_text_node_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';
|
import 'package:flowy_editor/service/keyboard_service.dart';
|
||||||
@ -26,12 +27,14 @@ class _FlowyEditorState extends State<FlowyEditor> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowySelection(
|
return FlowySelection(
|
||||||
key: selectionServiceKey,
|
key: editorState.service.selectionServiceKey,
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
child: FlowyKeyboard(
|
child: FlowyKeyboard(
|
||||||
|
key: editorState.service.keyboardServiceKey,
|
||||||
handlers: [
|
handlers: [
|
||||||
flowyDeleteNodesHandler,
|
flowyDeleteNodesHandler,
|
||||||
deleteSingleTextNodeHandler,
|
deleteSingleTextNodeHandler,
|
||||||
|
arrowKeysHandler,
|
||||||
...widget.keyEventHandler,
|
...widget.keyEventHandler,
|
||||||
],
|
],
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
|
@ -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;
|
||||||
|
};
|
@ -33,8 +33,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) {
|
|||||||
final previous = node!.previous! as TextNode;
|
final previous = node!.previous! as TextNode;
|
||||||
final newTextSelection = TextSelection.collapsed(
|
final newTextSelection = TextSelection.collapsed(
|
||||||
offset: previous.toRawString().length);
|
offset: previous.toRawString().length);
|
||||||
final selectionService =
|
final selectionService = editorState.service.selectionService;
|
||||||
selectionServiceKey.currentState as FlowySelectionService;
|
|
||||||
final previousSelectable =
|
final previousSelectable =
|
||||||
previous.key?.currentState?.unwrapOrNull<Selectable>();
|
previous.key?.currentState?.unwrapOrNull<Selectable>();
|
||||||
final newOfset = previousSelectable
|
final newOfset = previousSelectable
|
||||||
@ -58,8 +57,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) {
|
|||||||
..commit();
|
..commit();
|
||||||
final newTextSelection =
|
final newTextSelection =
|
||||||
TextSelection.collapsed(offset: textSelection.baseOffset - 1);
|
TextSelection.collapsed(offset: textSelection.baseOffset - 1);
|
||||||
final selectionService =
|
final selectionService = editorState.service.selectionService;
|
||||||
selectionServiceKey.currentState as FlowySelectionService;
|
|
||||||
final newOfset =
|
final newOfset =
|
||||||
selectable.getOffsetByTextSelection(newTextSelection);
|
selectable.getOffsetByTextSelection(newTextSelection);
|
||||||
selectionService.updateCursor(newOfset);
|
selectionService.updateCursor(newOfset);
|
||||||
|
@ -46,7 +46,7 @@ class _FlowyKeyboardState extends State<FlowyKeyboard> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final handler in widget.handlers) {
|
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);
|
KeyEventResult result = handler(widget.editorState, event);
|
||||||
|
|
||||||
|
@ -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');
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user