From 09adad3875f6d73b7d5c3d80135fcde5976c6b5c Mon Sep 17 00:00:00 2001 From: Jaylen Bian Date: Wed, 15 Sep 2021 23:51:22 +0800 Subject: [PATCH] [editor] Rename keyboard listener to avoid conflict with flutter widget --- .../lib/src/service/keyboard.dart | 4 +- .../lib/src/widget/raw_editor.dart | 199 ++++++------------ 2 files changed, 64 insertions(+), 139 deletions(-) diff --git a/app_flowy/packages/flowy_editor/lib/src/service/keyboard.dart b/app_flowy/packages/flowy_editor/lib/src/service/keyboard.dart index e3e4993b88..9ad94320da 100644 --- a/app_flowy/packages/flowy_editor/lib/src/service/keyboard.dart +++ b/app_flowy/packages/flowy_editor/lib/src/service/keyboard.dart @@ -28,8 +28,8 @@ typedef OnDeleteCallback = void Function( /* -------------------------------- Listener -------------------------------- */ -class KeyboardListener { - KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete); +class FlowyKeyboardListener { + FlowyKeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete); final CursorMoveCallback onCursorMove; final InputShortcutCallback onShortcut; diff --git a/app_flowy/packages/flowy_editor/lib/src/widget/raw_editor.dart b/app_flowy/packages/flowy_editor/lib/src/widget/raw_editor.dart index 3c62d02bc4..6173724efd 100644 --- a/app_flowy/packages/flowy_editor/lib/src/widget/raw_editor.dart +++ b/app_flowy/packages/flowy_editor/lib/src/widget/raw_editor.dart @@ -60,8 +60,7 @@ class RawEditor extends StatefulWidget { this.embedBuilder, ) : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'), assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'), - assert( - maxHeight == null || minHeight == null || maxHeight >= minHeight), + assert(maxHeight == null || minHeight == null || maxHeight >= minHeight), showCursor = showCursor ?? true, super(key: key); @@ -112,10 +111,7 @@ abstract class EditorState extends State { } class _RawEditorState extends EditorState - with - AutomaticKeepAliveClientMixin, - WidgetsBindingObserver, - TickerProviderStateMixin + with AutomaticKeepAliveClientMixin, WidgetsBindingObserver, TickerProviderStateMixin implements TextSelectionDelegate, TextInputClient { final GlobalKey _editorKey = GlobalKey(); final List _sentRemoteValues = []; @@ -129,12 +125,11 @@ class _RawEditorState extends EditorState ScrollController? _scrollController; KeyboardVisibilityController? _keyboardVisibilityController; StreamSubscription? _keyboardVisibilitySubscription; - late KeyboardListener _keyboardListener; + late FlowyKeyboardListener _keyboardListener; bool _didAutoFocus = false; bool _keyboardVisible = false; DefaultStyles? _styles; - final ClipboardStatusNotifier? _clipboardStatus = - kIsWeb ? null : ClipboardStatusNotifier(); + final ClipboardStatusNotifier? _clipboardStatus = kIsWeb ? null : ClipboardStatusNotifier(); final LayerLink _toolbarLayerLink = LayerLink(); final LayerLink _startHandleLayerLink = LayerLink(); final LayerLink _endHandleLayerLink = LayerLink(); @@ -182,78 +177,57 @@ class _RawEditorState extends EditorState downKey = key == LogicalKeyboardKey.arrowDown; if ((rightKey || leftKey) && !(rightKey && leftKey)) { - newSelection = _jumpToBeginOrEndOfWord(newSelection, wordModifier, - leftKey, rightKey, plainText, lineModifier, shift); + newSelection = + _jumpToBeginOrEndOfWord(newSelection, wordModifier, leftKey, rightKey, plainText, lineModifier, shift); } if (downKey || upKey) { - newSelection = _handleMovingCursorVertically( - upKey, downKey, shift, selection, newSelection, plainText); + newSelection = _handleMovingCursorVertically(upKey, downKey, shift, selection, newSelection, plainText); } if (!shift) { - newSelection = - _placeCollapsedSelection(selection, newSelection, leftKey, rightKey); + newSelection = _placeCollapsedSelection(selection, newSelection, leftKey, rightKey); } widget.controller.updateSelection(newSelection, ChangeSource.LOCAL); } - TextSelection _placeCollapsedSelection(TextSelection selection, - TextSelection newSelection, bool leftKey, bool rightKey) { + TextSelection _placeCollapsedSelection( + TextSelection selection, TextSelection newSelection, bool leftKey, bool rightKey) { var newOffset = newSelection.extentOffset; if (!selection.isCollapsed) { if (leftKey) { - newOffset = newSelection.baseOffset < newSelection.extentOffset - ? newSelection.baseOffset - : newSelection.extentOffset; + newOffset = + newSelection.baseOffset < newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset; } else if (rightKey) { - newOffset = newSelection.baseOffset > newSelection.extentOffset - ? newSelection.baseOffset - : newSelection.extentOffset; + newOffset = + newSelection.baseOffset > newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset; } } return TextSelection.fromPosition(TextPosition(offset: newOffset)); } TextSelection _handleMovingCursorVertically( - bool upKey, - bool downKey, - bool shift, - TextSelection selection, - TextSelection newSelection, - String plainText) { - final originPosition = TextPosition( - offset: upKey ? selection.baseOffset : selection.extentOffset); + bool upKey, bool downKey, bool shift, TextSelection selection, TextSelection newSelection, String plainText) { + final originPosition = TextPosition(offset: upKey ? selection.baseOffset : selection.extentOffset); final child = getRenderEditor()!.childAtPosition(originPosition); - final localPosition = TextPosition( - offset: originPosition.offset - child.container.documentOffset); + final localPosition = TextPosition(offset: originPosition.offset - child.container.documentOffset); - var position = upKey - ? child.getPositionAbove(localPosition) - : child.getPositionBelow(localPosition); + var position = upKey ? child.getPositionAbove(localPosition) : child.getPositionBelow(localPosition); if (position == null) { - final sibling = upKey - ? getRenderEditor()!.childBefore(child) - : getRenderEditor()!.childAfter(child); + final sibling = upKey ? getRenderEditor()!.childBefore(child) : getRenderEditor()!.childAfter(child); if (sibling == null) { position = TextPosition(offset: upKey ? 0 : plainText.length - 1); } else { - final finalOffset = Offset( - child.getOffsetForCaret(localPosition).dx, - sibling - .getOffsetForCaret(TextPosition( - offset: upKey ? sibling.container.length - 1 : 0)) - .dy); + final finalOffset = Offset(child.getOffsetForCaret(localPosition).dx, + sibling.getOffsetForCaret(TextPosition(offset: upKey ? sibling.container.length - 1 : 0)).dy); final siblingPosition = sibling.getPositionForOffset(finalOffset); - position = TextPosition( - offset: sibling.container.documentOffset + siblingPosition.offset); + position = TextPosition(offset: sibling.container.documentOffset + siblingPosition.offset); } } else { - position = TextPosition( - offset: child.container.documentOffset + position.offset); + position = TextPosition(offset: child.container.documentOffset + position.offset); } if (position.offset == newSelection.extentOffset) { @@ -276,47 +250,33 @@ class _RawEditorState extends EditorState return newSelection; } - TextSelection _jumpToBeginOrEndOfWord( - TextSelection newSelection, - bool wordModifier, - bool leftKey, - bool rightKey, - String plainText, - bool lineModifier, - bool shift) { + TextSelection _jumpToBeginOrEndOfWord(TextSelection newSelection, bool wordModifier, bool leftKey, bool rightKey, + String plainText, bool lineModifier, bool shift) { if (wordModifier) { if (leftKey) { final textSelection = getRenderEditor()!.selectWordAtPosition( - TextPosition( - offset: _previousCharacter( - newSelection.extentOffset, plainText, false))); + TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.baseOffset); } - final textSelection = getRenderEditor()!.selectWordAtPosition( - TextPosition( - offset: - _nextCharacter(newSelection.extentOffset, plainText, false))); + final textSelection = getRenderEditor()! + .selectWordAtPosition(TextPosition(offset: _nextCharacter(newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.extentOffset); } else if (lineModifier) { if (leftKey) { final textSelection = getRenderEditor()!.selectLineAtPosition( - TextPosition( - offset: _previousCharacter( - newSelection.extentOffset, plainText, false))); + TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.baseOffset); } final startPoint = newSelection.extentOffset; if (startPoint < plainText.length) { - final textSelection = getRenderEditor()! - .selectLineAtPosition(TextPosition(offset: startPoint)); + final textSelection = getRenderEditor()!.selectLineAtPosition(TextPosition(offset: startPoint)); return newSelection.copyWith(extentOffset: textSelection.extentOffset); } return newSelection; } if (rightKey && newSelection.extentOffset < plainText.length) { - final nextExtent = - _nextCharacter(newSelection.extentOffset, plainText, true); + final nextExtent = _nextCharacter(newSelection.extentOffset, plainText, true); final distance = nextExtent - newSelection.extentOffset; newSelection = newSelection.copyWith(extentOffset: nextExtent); if (shift) { @@ -326,8 +286,7 @@ class _RawEditorState extends EditorState } if (leftKey && newSelection.extentOffset > 0) { - final previousExtent = - _previousCharacter(newSelection.extentOffset, plainText, true); + final previousExtent = _previousCharacter(newSelection.extentOffset, plainText, true); final distance = newSelection.extentOffset - previousExtent; newSelection = newSelection.copyWith(extentOffset: previousExtent); if (shift) { @@ -367,9 +326,7 @@ class _RawEditorState extends EditorState var count = 0; int? lastNonWhitespace; for (final currentString in string.characters) { - if (!includeWhitespace && - !WHITE_SPACE.contains( - currentString.characters.first.toString().codeUnitAt(0))) { + if (!includeWhitespace && !WHITE_SPACE.contains(currentString.characters.first.toString().codeUnitAt(0))) { lastNonWhitespace = count; } if (count + currentString.length >= index) { @@ -380,8 +337,7 @@ class _RawEditorState extends EditorState return 0; } - bool get hasConnection => - _textInputConnection != null && _textInputConnection!.attached; + bool get hasConnection => _textInputConnection != null && _textInputConnection!.attached; void openConnectionIfNeeded() { if (!shouldCreateInputConnection) { @@ -432,8 +388,7 @@ class _RawEditorState extends EditorState return; } - final shouldRemember = - textEditingValue.text != _lastKnownRemoteTextEditingValue!.text; + final shouldRemember = textEditingValue.text != _lastKnownRemoteTextEditingValue!.text; _lastKnownRemoteTextEditingValue = actualValue; _textInputConnection!.setEditingState(actualValue); if (shouldRemember) { @@ -442,8 +397,7 @@ class _RawEditorState extends EditorState } @override - TextEditingValue? get currentTextEditingValue => - _lastKnownRemoteTextEditingValue; + TextEditingValue? get currentTextEditingValue => _lastKnownRemoteTextEditingValue; @override AutofillScope? get currentAutofillScope => null; @@ -475,8 +429,7 @@ class _RawEditorState extends EditorState final text = value.text; final cursorPosition = value.selection.extentOffset; final diff = getDiff(oldText, text, cursorPosition); - widget.controller.replaceText( - diff.start, diff.deleted.length, diff.inserted, value.selection); + widget.controller.replaceText(diff.start, diff.deleted.length, diff.inserted, value.selection); } @override @@ -526,11 +479,8 @@ class _RawEditorState extends EditorState super.build(context); var _doc = widget.controller.document; - if (_doc.isEmpty() && - !widget.focusNode.hasFocus && - widget.placeholder != null) { - _doc = Document.fromJson(jsonDecode( - '[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]')); + if (_doc.isEmpty() && !widget.focusNode.hasFocus && widget.placeholder != null) { + _doc = Document.fromJson(jsonDecode('[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]')); } Widget child = CompositedTransformTarget( @@ -553,8 +503,7 @@ class _RawEditorState extends EditorState ); if (widget.scrollable) { - final baselinePadding = - EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1); + final baselinePadding = EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1); child = BaselineProxy( textStyle: _styles!.paragraph!.style, padding: baselinePadding, @@ -585,8 +534,7 @@ class _RawEditorState extends EditorState ); } - void _handleSelectionChanged( - TextSelection selection, SelectionChangedCause cause) { + void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) { widget.controller.updateSelection(selection, ChangeSource.LOCAL); _selectionOverlay?.handlesVisible = _shouldShowSelectionHandles(); @@ -615,9 +563,7 @@ class _RawEditorState extends EditorState _styles, widget.enableInteractiveSelection, _hasFocus, - attrs.containsKey(Attribute.codeBlock.key) - ? const EdgeInsets.all(16) - : null, + attrs.containsKey(Attribute.codeBlock.key) ? const EdgeInsets.all(16) : null, widget.embedBuilder, _cursorController, indentLevelCounts); @@ -629,8 +575,7 @@ class _RawEditorState extends EditorState return result; } - EditableTextLine _getEditableTextLineFromNode( - Line node, BuildContext context) { + EditableTextLine _getEditableTextLineFromNode(Line node, BuildContext context) { final textLine = TextLine( line: node, textDirection: _textDirection, @@ -653,8 +598,7 @@ class _RawEditorState extends EditorState return editableTextLine; } - Tuple2 _getVerticalSpacingForLine( - Line line, DefaultStyles? defaultStyles) { + Tuple2 _getVerticalSpacingForLine(Line line, DefaultStyles? defaultStyles) { final attrs = line.style.attributes; if (attrs.containsKey(Attribute.header.key)) { final int? level = attrs[Attribute.header.key]!.value; @@ -679,8 +623,7 @@ class _RawEditorState extends EditorState return defaultStyles!.paragraph!.verticalSpacing; } - Tuple2 _getVerticalSpacingForBlock( - Block node, DefaultStyles? defaultStyles) { + Tuple2 _getVerticalSpacingForBlock(Block node, DefaultStyles? defaultStyles) { final attrs = node.style.attributes; if (attrs.containsKey(Attribute.quoteBlock.key)) { return defaultStyles!.quote!.verticalSpacing; @@ -709,7 +652,7 @@ class _RawEditorState extends EditorState tickerProvider: this, ); - _keyboardListener = KeyboardListener( + _keyboardListener = FlowyKeyboardListener( handleCursorMovement, handleShortcut, handleDelete, @@ -723,8 +666,7 @@ class _RawEditorState extends EditorState } else { _keyboardVisibilityController = KeyboardVisibilityController(); _keyboardVisible = _keyboardVisibilityController!.isVisible; - _keyboardVisibilitySubscription = - _keyboardVisibilityController?.onChange.listen((visible) { + _keyboardVisibilitySubscription = _keyboardVisibilityController?.onChange.listen((visible) { _keyboardVisible = visible; if (visible) { _onChangeTextEditingValue(); @@ -747,9 +689,7 @@ class _RawEditorState extends EditorState super.didChangeDependencies(); final parentStyles = EditorStyles.getStyles(context, true); final defaultStyles = DefaultStyles.getInstance(context); - _styles = (parentStyles != null) - ? defaultStyles.merge(parentStyles) - : defaultStyles; + _styles = (parentStyles != null) ? defaultStyles.merge(parentStyles) : defaultStyles; if (widget.customStyles != null) { _styles = _styles!.merge(widget.customStyles!); @@ -809,8 +749,7 @@ class _RawEditorState extends EditorState } bool _shouldShowSelectionHandles() { - return widget.showSelectionHandles && - !widget.controller.selection.isCollapsed; + return widget.showSelectionHandles && !widget.controller.selection.isCollapsed; } void handleDelete(bool forward) { @@ -821,8 +760,7 @@ class _RawEditorState extends EditorState var textAfter = selection.textAfter(plainText); if (selection.isCollapsed) { if (!forward && textBefore.isNotEmpty) { - final characterBoundary = - _previousCharacter(textBefore.length, textBefore, true); + final characterBoundary = _previousCharacter(textBefore.length, textBefore, true); textBefore = textBefore.substring(0, characterBoundary); cursorPosition = characterBoundary; } @@ -851,8 +789,7 @@ class _RawEditorState extends EditorState } if (shortcut == InputShortcut.COPY) { if (!selection.isCollapsed) { - await Clipboard.setData( - ClipboardData(text: selection.textInside(plainText))); + await Clipboard.setData(ClipboardData(text: selection.textInside(plainText))); } return; } @@ -869,8 +806,7 @@ class _RawEditorState extends EditorState ); textEditingValue = TextEditingValue( - text: - selection.textBefore(plainText) + selection.textAfter(plainText), + text: selection.textBefore(plainText) + selection.textAfter(plainText), selection: TextSelection.collapsed(offset: selection.start), ); } @@ -888,8 +824,7 @@ class _RawEditorState extends EditorState } return; } - if (shortcut == InputShortcut.SELECT_ALL && - widget.enableInteractiveSelection) { + if (shortcut == InputShortcut.SELECT_ALL && widget.enableInteractiveSelection) { widget.controller.updateSelection( selection.copyWith( baseOffset: 0, @@ -943,16 +878,14 @@ class _RawEditorState extends EditorState void _onChangeTextEditingValue() { _showCaretOnScreen(); updateRemoteValueIfNeeded(); - _cursorController.startOrStopCursorTimerIfNeeded( - _hasFocus, widget.controller.selection); + _cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection); if (hasConnection) { _cursorController ..stopCursorTimer(resetCharTicks: false) ..startCursorTimer(); } - SchedulerBinding.instance!.addPostFrameCallback( - (_) => _updateOrDisposeSelectionOverlayIfNeeded()); + SchedulerBinding.instance!.addPostFrameCallback((_) => _updateOrDisposeSelectionOverlayIfNeeded()); if (mounted) { setState(() { // Use widget.controller.value in build() @@ -995,8 +928,7 @@ class _RawEditorState extends EditorState void _handleFocusChanged() { openOrCloseConnection(); - _cursorController.startOrStopCursorTimerIfNeeded( - _hasFocus, widget.controller.selection); + _cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection); _updateOrDisposeSelectionOverlayIfNeeded(); if (_hasFocus) { WidgetsBinding.instance!.addObserver(this); @@ -1027,8 +959,7 @@ class _RawEditorState extends EditorState _showCaretOnScreenScheduled = false; final viewport = RenderAbstractViewport.of(getRenderEditor())!; - final editorOffset = getRenderEditor()! - .localToGlobal(const Offset(0, 0), ancestor: viewport); + final editorOffset = getRenderEditor()!.localToGlobal(const Offset(0, 0), ancestor: viewport); final offsetInViewport = _scrollController!.offset + editorOffset.dy; final offset = getRenderEditor()!.getOffsetToRevealCursor( @@ -1111,8 +1042,7 @@ class _RawEditorState extends EditorState final value = textEditingValue; final data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null) { - final length = - textEditingValue.selection.end - textEditingValue.selection.start; + final length = textEditingValue.selection.end - textEditingValue.selection.start; widget.controller.replaceText( value.selection.start, length, @@ -1121,9 +1051,7 @@ class _RawEditorState extends EditorState ); // move cursor to the end of pasted text selection widget.controller.updateSelection( - TextSelection.collapsed( - offset: value.selection.start + data.text!.length), - ChangeSource.LOCAL); + TextSelection.collapsed(offset: value.selection.start + data.text!.length), ChangeSource.LOCAL); } } } @@ -1133,8 +1061,7 @@ class _RawEditorState extends EditorState if (data == null) { return false; } - return textEditingValue.text.length - value.text.length == - data.text!.length; + return textEditingValue.text.length - value.text.length == data.text!.length; } @override @@ -1167,8 +1094,7 @@ class _RawEditorState extends EditorState } @override - void userUpdateTextEditingValue( - TextEditingValue value, SelectionChangedCause cause) { + void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) { // TODO: implement userUpdateTextEditingValue } } @@ -1218,8 +1144,7 @@ class _Editor extends MultiChildRenderObjectWidget { } @override - void updateRenderObject( - BuildContext context, covariant RenderEditor renderObject) { + void updateRenderObject(BuildContext context, covariant RenderEditor renderObject) { renderObject ..document = document ..container = document.root