From d0495847855a2f409c80b19b82d5025a5c9e980a Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 30 Sep 2024 09:21:19 +0800 Subject: [PATCH] feat: support keyboard gesture on mobile (#905) * feat: support keyboard gesture on mobile * fix: update drag handle when typing text on iOS --- ...delta_input_on_floating_cursor_update.dart | 32 +++++++++++++++++-- .../delta_input_on_non_text_update_impl.dart | 20 ++++++++++++ .../service/ime/non_delta_input_service.dart | 3 ++ .../selection/mobile_selection_service.dart | 8 +++-- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart index 68eee1dae..2254784f5 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_floating_cursor_update.dart @@ -11,8 +11,9 @@ Future onFloatingCursorUpdate( RawFloatingCursorPoint point, EditorState editorState, ) async { - AppFlowyEditorLog.input - .debug('onFloatingCursorUpdate: ${point.state}, ${point.offset}'); + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdate: ${point.state}, ${point.offset}', + ); // support updating the cursor position via the space bar on iOS/Android. if (PlatformExtension.isDesktopOrWeb) { @@ -26,9 +27,16 @@ Future onFloatingCursorUpdate( final collapsedCursor = HandleType.collapsed.key; final context = collapsedCursor.currentContext; if (context == null) { + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateStart: context is null', + ); return; } + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateStart: ${point.startLocation}', + ); + // get global offset of the cursor. final renderBox = context.findRenderObject() as RenderBox; final offset = renderBox.localToGlobal(Offset.zero); @@ -44,10 +52,26 @@ Future onFloatingCursorUpdate( ); break; case FloatingCursorDragState.Update: + final collapsedCursor = HandleType.collapsed.key; + final context = collapsedCursor.currentContext; + if (context == null) { + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateUpdate: context is null', + ); + return; + } else { + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateUpdate: context is not null', + ); + } if (_cursorOffset == null || point.offset == null) { return; } + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateUpdate: ${point.offset}', + ); + disableMagnifier = true; selectionService.onPanUpdate( DragUpdateDetails( @@ -57,6 +81,10 @@ Future onFloatingCursorUpdate( ); break; case FloatingCursorDragState.End: + AppFlowyEditorLog.input.debug( + 'onFloatingCursorUpdateEnd: ${point.offset}', + ); + _cursorOffset = null; disableMagnifier = false; selectionService.onPanEnd( diff --git a/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart b/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart index 90fe0dede..958d2dbd3 100644 --- a/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart +++ b/lib/src/editor/editor_component/service/ime/delta_input_on_non_text_update_impl.dart @@ -53,6 +53,26 @@ Future onNonTextUpdate( ), ); } + } else if (PlatformExtension.isAndroid) { + // on some Android keyboards (e.g. Gboard), they use non-text update to update the selection when moving cursor + // by space bar. + // for the another keyboards (e.g. system keyboard), they will trigger the + // `onFloatingCursor` event instead. + AppFlowyEditorLog.input.debug('[Android] onNonTextUpdate: $nonTextUpdate'); + if (selection != null) { + editorState.updateSelectionWithReason( + Selection.collapsed( + Position( + path: selection.start.path, + offset: nonTextUpdate.selection.start, + ), + ), + ); + } + } else if (PlatformExtension.isIOS) { + // on iOS, the cursor movement will trigger the `onFloatingCursor` event. + // so we don't need to handle the non-text update here. + AppFlowyEditorLog.input.debug('[iOS] onNonTextUpdate: $nonTextUpdate'); } } diff --git a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart index 3316ff3bb..256d714c8 100644 --- a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart @@ -106,6 +106,9 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { // on iOS, when using gesture to move cursor, this function will be called // which may cause the unneeded delta being applied // so we ignore the updateEditingValue event when the floating cursor is visible + AppFlowyEditorLog.editor.debug( + 'ignore updateEditingValue event when the floating cursor is visible', + ); return; } diff --git a/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart b/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart index f204f5cbd..7f2eeba23 100644 --- a/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart +++ b/lib/src/editor/editor_component/service/selection/mobile_selection_service.dart @@ -177,8 +177,12 @@ class _MobileSelectionServiceWidgetState return ValueListenableBuilder( valueListenable: selectionNotifierAfterLayout, builder: (context, selection, _) { - if (selection == null || - !selection.isCollapsed || + if (selection == null || !selection.isCollapsed) { + return const SizedBox.shrink(); + } + + // on iOS, the drag handle should be updated when typing text. + if (PlatformExtension.isAndroid && editorState.selectionUpdateReason != SelectionUpdateReason.uiEvent) { return const SizedBox.shrink();