From cb6f85d662f4dab5aed56de3c86209450c8913e1 Mon Sep 17 00:00:00 2001 From: Angelo Silvestre Date: Wed, 22 May 2024 00:49:57 -0300 Subject: [PATCH] [SuperEditor][Mobile] Add caret customization (Resolves #1935) (#2020) --- .../document_gestures_touch_android.dart | 4 ++ .../document_gestures_touch_ios.dart | 13 +++++ .../android/android_document_controls.dart | 5 +- .../platforms/ios/ios_document_controls.dart | 21 ++++--- .../platforms/ios/selection_handles.dart | 4 +- .../super_editor/supereditor_test_tools.dart | 48 ++++++++++++++-- ...uper-editor-android-custom-caret-width.png | Bin 0 -> 23423 bytes .../super-editor-ios-custom-caret-width.png | Bin 0 -> 21852 bytes ...editor-ios-custom-handle-ball-diameter.png | Bin 0 -> 30944 bytes .../super-editor-ios-custom-handle-width.png | Bin 0 -> 30321 bytes .../editor/supereditor_caret_test.dart | 53 ++++++++++++++++++ 11 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 super_editor/test_goldens/editor/goldens/super-editor-android-custom-caret-width.png create mode 100644 super_editor/test_goldens/editor/goldens/super-editor-ios-custom-caret-width.png create mode 100644 super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-ball-diameter.png create mode 100644 super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-width.png diff --git a/super_editor/lib/src/default_editor/document_gestures_touch_android.dart b/super_editor/lib/src/default_editor/document_gestures_touch_android.dart index dc5bdbedf..c7d4de69b 100644 --- a/super_editor/lib/src/default_editor/document_gestures_touch_android.dart +++ b/super_editor/lib/src/default_editor/document_gestures_touch_android.dart @@ -353,6 +353,7 @@ class SuperEditorAndroidToolbarFocalPointDocumentLayerBuilder implements SuperEd class SuperEditorAndroidHandlesDocumentLayerBuilder implements SuperEditorLayerBuilder { const SuperEditorAndroidHandlesDocumentLayerBuilder({ this.caretColor, + this.caretWidth = 2, }); /// The (optional) color of the caret (not the drag handle), by default the color @@ -360,6 +361,8 @@ class SuperEditorAndroidHandlesDocumentLayerBuilder implements SuperEditorLayerB /// controls controller has no preference for the color. final Color? caretColor; + final double caretWidth; + @override ContentLayerWidget build(BuildContext context, SuperEditorContext editContext) { if (defaultTargetPlatform != TargetPlatform.android || @@ -379,6 +382,7 @@ class SuperEditorAndroidHandlesDocumentLayerBuilder implements SuperEditorLayerB const ClearComposingRegionRequest(), ]); }, + caretWidth: caretWidth, caretColor: caretColor, ); } diff --git a/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart b/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart index de9154653..356264ce1 100644 --- a/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart +++ b/super_editor/lib/src/default_editor/document_gestures_touch_ios.dart @@ -1838,9 +1838,16 @@ class SuperEditorIosToolbarFocalPointDocumentLayerBuilder implements SuperEditor class SuperEditorIosHandlesDocumentLayerBuilder implements SuperEditorLayerBuilder { const SuperEditorIosHandlesDocumentLayerBuilder({ this.handleColor, + this.caretWidth, + this.handleBallDiameter, }); final Color? handleColor; + final double? caretWidth; + + /// The diameter of the small circle that appears on the top and bottom of + /// expanded iOS text handles. + final double? handleBallDiameter; @override ContentLayerWidget build(BuildContext context, SuperEditorContext editContext) { @@ -1863,6 +1870,8 @@ class SuperEditorIosHandlesDocumentLayerBuilder implements SuperEditorLayerBuild handleColor: handleColor ?? SuperEditorIosControlsScope.maybeRootOf(context)?.handleColor ?? Theme.of(context).primaryColor, + caretWidth: caretWidth ?? 2, + handleBallDiameter: handleBallDiameter ?? defaultIosHandleBallDiameter, shouldCaretBlink: SuperEditorIosControlsScope.rootOf(context).shouldCaretBlink, floatingCursorController: SuperEditorIosControlsScope.rootOf(context).floatingCursorController, ); @@ -1873,3 +1882,7 @@ const defaultIosMagnifierEnterAnimationDuration = Duration(milliseconds: 180); const defaultIosMagnifierExitAnimationDuration = Duration(milliseconds: 150); const defaultIosMagnifierAnimationCurve = Curves.easeInOut; const defaultIosMagnifierSize = Size(133, 96); + +/// The diameter of the small circle that appears on the top and bottom of +/// expanded iOS text handles. +const defaultIosHandleBallDiameter = 8.0; diff --git a/super_editor/lib/src/infrastructure/platforms/android/android_document_controls.dart b/super_editor/lib/src/infrastructure/platforms/android/android_document_controls.dart index 2c451d41e..db4630228 100644 --- a/super_editor/lib/src/infrastructure/platforms/android/android_document_controls.dart +++ b/super_editor/lib/src/infrastructure/platforms/android/android_document_controls.dart @@ -151,6 +151,7 @@ class AndroidHandlesDocumentLayer extends DocumentLayoutLayerStatefulWidget { required this.documentLayout, required this.selection, required this.changeSelection, + this.caretWidth = 2, this.caretColor, this.showDebugPaint = false, }); @@ -163,6 +164,8 @@ class AndroidHandlesDocumentLayer extends DocumentLayoutLayerStatefulWidget { final void Function(DocumentSelection?, SelectionChangeType, String selectionReason) changeSelection; + final double caretWidth; + /// Color used to render the Android-style caret (not handles), by default the color /// is retrieved from the root [SuperEditorAndroidControlsController]. final Color? caretColor; @@ -387,7 +390,7 @@ class AndroidControlsDocumentLayerState left: caret.left, top: caret.top, height: caret.height, - width: 2, + width: widget.caretWidth, child: Leader( link: _controlsController!.collapsedHandleFocalPoint, child: ListenableBuilder( diff --git a/super_editor/lib/src/infrastructure/platforms/ios/ios_document_controls.dart b/super_editor/lib/src/infrastructure/platforms/ios/ios_document_controls.dart index 59ab129bb..5f4be580b 100644 --- a/super_editor/lib/src/infrastructure/platforms/ios/ios_document_controls.dart +++ b/super_editor/lib/src/infrastructure/platforms/ios/ios_document_controls.dart @@ -504,6 +504,8 @@ class IosHandlesDocumentLayer extends DocumentLayoutLayerStatefulWidget { required this.selection, required this.changeSelection, required this.handleColor, + this.caretWidth = 2, + this.handleBallDiameter = defaultIosHandleBallDiameter, required this.shouldCaretBlink, this.floatingCursorController, this.showDebugPaint = false, @@ -520,6 +522,12 @@ class IosHandlesDocumentLayer extends DocumentLayoutLayerStatefulWidget { /// Color the iOS-style text selection drag handles. final Color handleColor; + final double caretWidth; + + /// The diameter of the small circle that appears on the top and bottom of + /// expanded iOS text handles. + final double handleBallDiameter; + /// Whether the caret should blink, whenever the caret is visible. final ValueListenable shouldCaretBlink; @@ -538,10 +546,6 @@ class IosHandlesDocumentLayer extends DocumentLayoutLayerStatefulWidget { @visibleForTesting class IosControlsDocumentLayerState extends DocumentLayoutLayerState with SingleTickerProviderStateMixin { - /// The diameter of the small circle that appears on the top and bottom of - /// expanded iOS text handles. - static const ballDiameter = 8.0; - // These global keys are assigned to each draggable handle to // prevent a strange dragging issue. // @@ -775,6 +779,7 @@ class IosControlsDocumentLayerState extends DocumentLayoutLayerState { List _createOverlayBuilders() { // We show the default overlays except in the cases where we want to hide the caret - // or use a custom `CaretStyle`. In those case, we don't include the defaults - we provide + // or use a custom caret style. In those case, we don't include the defaults - we provide // a configured caret overlay builder, instead. // // If you introduce further configuration to overlay builders, make sure that in the default // situation, we're using `defaultSuperEditorDocumentOverlayBuilders`, so that most tests // verify the defaults that most apps will use. - if (widget.testConfiguration.displayCaretWithExpandedSelection && widget.testConfiguration.caretStyle == null) { + if (widget.testConfiguration.displayCaretWithExpandedSelection && + widget.testConfiguration.caretStyle == null && + widget.testConfiguration.iosCaretWidth == null && + widget.testConfiguration.iosHandleColor == null && + widget.testConfiguration.iosHandleBallDiameter == null && + widget.testConfiguration.androidCaretWidth == null) { return defaultSuperEditorDocumentOverlayBuilders; } @@ -578,13 +603,20 @@ class _TestSuperEditorState extends State<_TestSuperEditor> { // iOS floating toolbar. const SuperEditorIosToolbarFocalPointDocumentLayerBuilder(), // Displays caret and drag handles, specifically for iOS. - const SuperEditorIosHandlesDocumentLayerBuilder(), + SuperEditorIosHandlesDocumentLayerBuilder( + caretWidth: widget.testConfiguration.iosCaretWidth, + handleColor: widget.testConfiguration.iosHandleColor, + handleBallDiameter: widget.testConfiguration.iosHandleBallDiameter, + ), // Adds a Leader around the document selection at a focal point for the // Android floating toolbar. const SuperEditorAndroidToolbarFocalPointDocumentLayerBuilder(), // Displays caret and drag handles, specifically for Android. - const SuperEditorAndroidHandlesDocumentLayerBuilder(), + SuperEditorAndroidHandlesDocumentLayerBuilder( + caretWidth: widget.testConfiguration.androidCaretWidth ?? 2.0, + caretColor: widget.testConfiguration.androidCaretColor, + ), // Displays caret for typical desktop use-cases. DefaultCaretOverlayBuilder( @@ -618,6 +650,14 @@ class SuperEditorTestConfiguration { SelectionStyles? selectionStyles; bool displayCaretWithExpandedSelection = true; CaretStyle? caretStyle; + + double? iosCaretWidth; + Color? iosHandleColor; + double? iosHandleBallDiameter; + + double? androidCaretWidth; + Color? androidCaretColor; + SoftwareKeyboardController? softwareKeyboardController; SuperEditorImePolicies? imePolicies; SuperEditorImeConfiguration? imeConfiguration; diff --git a/super_editor/test_goldens/editor/goldens/super-editor-android-custom-caret-width.png b/super_editor/test_goldens/editor/goldens/super-editor-android-custom-caret-width.png new file mode 100644 index 0000000000000000000000000000000000000000..4da8f082fb90a6faca69065151f2d49556ccd3f7 GIT binary patch literal 23423 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 ZI1R~l8%nE7;&{|I4)kB=SL7Rh@E?ZnuVw%M literal 0 HcmV?d00001 diff --git a/super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-ball-diameter.png b/super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-ball-diameter.png new file mode 100644 index 0000000000000000000000000000000000000000..c56e9b6d908f88861c1ea19453a8daeea9e2c757 GIT binary patch literal 30944 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 literal 0 HcmV?d00001 diff --git a/super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-width.png b/super_editor/test_goldens/editor/goldens/super-editor-ios-custom-handle-width.png new file mode 100644 index 0000000000000000000000000000000000000000..82d8ab66e4f89f94e75ff71c94a0b18aaeb9ae42 GIT binary patch literal 30321 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