Merge pull request #824 from AppFlowy-IO/feat/handle-edit-keys

Feat: handle edit keys
This commit is contained in:
Vincent Chan 2022-08-11 19:08:53 +08:00 committed by GitHub
commit c53df59b48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 23 deletions

View File

@ -1,5 +1,4 @@
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_editor/src/service/keyboard_service.dart';
import 'package:flowy_editor/src/infra/html_converter.dart';
import 'package:flowy_editor/src/document/node_iterator.dart';
import 'package:flutter/material.dart';

View File

@ -7,6 +7,8 @@ import 'package:flowy_editor/src/service/internal_key_event_handlers/redo_undo_h
import 'package:flowy_editor/src/service/internal_key_event_handlers/slash_handler.dart';
import 'package:flowy_editor/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart';
import 'package:flowy_editor/src/service/internal_key_event_handlers/whitespace_handler.dart';
import 'package:flowy_editor/src/service/internal_key_event_handlers/select_all_handler.dart';
import 'package:flowy_editor/src/service/internal_key_event_handlers/page_up_down_handler.dart';
import 'package:flowy_editor/src/service/keyboard_service.dart';
List<FlowyKeyEventHandler> defaultKeyEventHandlers = [
@ -19,4 +21,6 @@ List<FlowyKeyEventHandler> defaultKeyEventHandlers = [
enterWithoutShiftInTextNodesHandler,
updateTextStyleByCommandXHandler,
whiteSpaceHandler,
selectAllHandler,
pageUpDownHandler,
];

View File

@ -2,14 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_editor/src/service/keyboard_service.dart';
// Handle delete text.
FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
if (event.logicalKey != LogicalKeyboardKey.backspace) {
return KeyEventResult.ignored;
}
KeyEventResult _handleBackspace(EditorState editorState, RawKeyEvent event) {
final selection = editorState.service.selectionService.currentSelection.value;
if (selection == null) {
return KeyEventResult.ignored;
@ -22,7 +16,7 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
return KeyEventResult.ignored;
}
TransactionBuilder transactionBuilder = TransactionBuilder(editorState);
final transactionBuilder = TransactionBuilder(editorState);
if (textNodes.length == 1) {
final textNode = textNodes.first;
final index = textNode.delta.prevRunePosition(selection.start.offset);
@ -74,23 +68,90 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
}
}
} else {
final first = textNodes.first;
final last = textNodes.last;
var content = textNodes.last.toRawString();
content = content.substring(selection.end.offset, content.length);
// Merge the fist and the last text node content,
// and delete the all nodes expect for the first.
transactionBuilder
..deleteNodes(textNodes.sublist(1))
..mergeText(
first,
last,
firstOffset: selection.start.offset,
secondOffset: selection.end.offset,
);
_deleteNodes(transactionBuilder, textNodes, selection);
}
transactionBuilder.commit();
return KeyEventResult.handled;
}
KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
final selection = editorState.service.selectionService.currentSelection.value;
if (selection == null) {
return KeyEventResult.ignored;
}
final nodes = editorState.service.selectionService.currentSelectedNodes;
// make sure all nodes is [TextNode].
final textNodes = nodes.whereType<TextNode>().toList();
if (textNodes.length != nodes.length) {
return KeyEventResult.ignored;
}
final transactionBuilder = TransactionBuilder(editorState);
if (textNodes.length == 1) {
final textNode = textNodes.first;
if (selection.start.offset >= textNode.delta.length) {
debugPrint("merge next line");
final nextNode = textNode.next;
if (nextNode == null) {
return KeyEventResult.ignored;
}
if (nextNode is TextNode) {
transactionBuilder.mergeText(textNode, nextNode);
}
transactionBuilder.deleteNode(nextNode);
} else {
final index = textNode.delta.nextRunePosition(selection.start.offset);
if (selection.isCollapsed) {
transactionBuilder.deleteText(
textNode,
selection.start.offset,
index - selection.start.offset,
);
} else {
transactionBuilder.deleteText(
textNode,
selection.start.offset,
selection.end.offset - selection.start.offset,
);
}
}
} else {
_deleteNodes(transactionBuilder, textNodes, selection);
}
transactionBuilder.commit();
return KeyEventResult.handled;
}
void _deleteNodes(TransactionBuilder transactionBuilder,
List<TextNode> textNodes, Selection selection) {
final first = textNodes.first;
final last = textNodes.last;
var content = textNodes.last.toRawString();
content = content.substring(selection.end.offset, content.length);
// Merge the fist and the last text node content,
// and delete the all nodes expect for the first.
transactionBuilder
..deleteNodes(textNodes.sublist(1))
..mergeText(
first,
last,
firstOffset: selection.start.offset,
secondOffset: selection.end.offset,
);
}
// Handle delete text.
FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
if (event.logicalKey == LogicalKeyboardKey.backspace) {
return _handleBackspace(editorState, event);
}
if (event.logicalKey == LogicalKeyboardKey.delete) {
return _handleDelete(editorState, event);
}
return KeyEventResult.ignored;
};

View File

@ -0,0 +1,31 @@
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
double? getEditorHeight(EditorState editorState) {
final renderObj =
editorState.service.scrollServiceKey.currentContext?.findRenderObject();
if (renderObj is RenderBox) {
return renderObj.size.height;
}
return null;
}
FlowyKeyEventHandler pageUpDownHandler = (editorState, event) {
if (event.logicalKey == LogicalKeyboardKey.pageUp) {
final scrollHeight = getEditorHeight(editorState);
final scrollService = editorState.service.scrollService;
if (scrollHeight != null && scrollService != null) {
scrollService.scrollTo(scrollService.dy - scrollHeight);
}
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.pageDown) {
final scrollHeight = getEditorHeight(editorState);
final scrollService = editorState.service.scrollService;
if (scrollHeight != null && scrollService != null) {
scrollService.scrollTo(scrollService.dy + scrollHeight);
}
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
};

View File

@ -0,0 +1,26 @@
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
KeyEventResult _selectAll(EditorState editorState) {
if (editorState.document.root.children.isEmpty) {
return KeyEventResult.handled;
}
final firstNode = editorState.document.root.children.first;
final lastNode = editorState.document.root.children.last;
var offset = 0;
if (lastNode is TextNode) {
offset = lastNode.delta.length;
}
editorState.updateCursorSelection(Selection(
start: Position(path: firstNode.path, offset: 0),
end: Position(path: lastNode.path, offset: offset)));
return KeyEventResult.handled;
}
FlowyKeyEventHandler selectAllHandler = (editorState, event) {
if (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyA) {
return _selectAll(editorState);
}
return KeyEventResult.ignored;
};