@@ -156,6 +156,25 @@ class SuperEditorIosControlsController {
156
156
/// Tells the caret to stop blinking by setting [shouldCaretBlink] to `false` .
157
157
void doNotBlinkCaret () => _shouldCaretBlink.value = false ;
158
158
159
+ /// {@macro are_selection_handles_allowed}
160
+ ValueListenable <bool > get areSelectionHandlesAllowed => _areSelectionHandlesAllowed;
161
+ final _areSelectionHandlesAllowed = ValueNotifier <bool >(true );
162
+
163
+ /// Temporarily prevents any selection handles from being displayed.
164
+ ///
165
+ /// Call this when you want to select some content, but don't want to show the drag handles.
166
+ /// [allowSelectionHandles] must be called to allow the drag handles to be displayed again.
167
+ void allowSelectionHandles () => _areSelectionHandlesAllowed.value = true ;
168
+
169
+ /// Allows the selection handles to be displayed after they have been temporarily
170
+ /// prevented by [preventSelectionHandles] .
171
+ void preventSelectionHandles () => _areSelectionHandlesAllowed.value = false ;
172
+
173
+ /// Reports the [HandleType] of the handle being dragged by the user.
174
+ ///
175
+ /// If no drag handle is being dragged, this value is `null` .
176
+ final ValueNotifier <HandleType ?> handleBeingDragged = ValueNotifier <HandleType ?>(null );
177
+
159
178
/// Controls the iOS floating cursor.
160
179
late final FloatingCursorController floatingCursorController;
161
180
@@ -580,14 +599,6 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
580
599
..hideMagnifier ()
581
600
..blinkCaret ();
582
601
583
- final selection = widget.selection.value;
584
- if (selection != null &&
585
- ! selection.isCollapsed &&
586
- (_isOverBaseHandle (details.localPosition) || _isOverExtentHandle (details.localPosition))) {
587
- _controlsController! .toggleToolbar ();
588
- return ;
589
- }
590
-
591
602
editorGesturesLog.info ("Tap down on document" );
592
603
final docOffset = _interactorOffsetToDocumentOffset (details.localPosition);
593
604
editorGesturesLog.fine (" - document offset: $docOffset " );
@@ -609,6 +620,14 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
609
620
}
610
621
}
611
622
623
+ final selection = widget.selection.value;
624
+ if (selection != null &&
625
+ ! selection.isCollapsed &&
626
+ (_isOverBaseHandle (details.localPosition) || _isOverExtentHandle (details.localPosition))) {
627
+ _controlsController! .toggleToolbar ();
628
+ return ;
629
+ }
630
+
612
631
final docPosition = _docLayout.getDocumentPositionNearestToOffset (docOffset);
613
632
editorGesturesLog.fine (" - tapped document position: $docPosition " );
614
633
if (docPosition != null &&
@@ -713,13 +732,6 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
713
732
}
714
733
715
734
void _onDoubleTapUp (TapUpDetails details) {
716
- final selection = widget.selection.value;
717
- if (selection != null &&
718
- ! selection.isCollapsed &&
719
- (_isOverBaseHandle (details.localPosition) || _isOverExtentHandle (details.localPosition))) {
720
- return ;
721
- }
722
-
723
735
editorGesturesLog.info ("Double tap down on document" );
724
736
final docOffset = _interactorOffsetToDocumentOffset (details.localPosition);
725
737
editorGesturesLog.fine (" - document offset: $docOffset " );
@@ -741,6 +753,13 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
741
753
}
742
754
}
743
755
756
+ final selection = widget.selection.value;
757
+ if (selection != null &&
758
+ ! selection.isCollapsed &&
759
+ (_isOverBaseHandle (details.localPosition) || _isOverExtentHandle (details.localPosition))) {
760
+ return ;
761
+ }
762
+
744
763
final docPosition = _docLayout.getDocumentPositionNearestToOffset (docOffset);
745
764
editorGesturesLog.fine (" - tapped document position: $docPosition " );
746
765
if (docPosition != null ) {
@@ -871,6 +890,24 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
871
890
_globalTapDownOffset = null ;
872
891
_tapDownLongPressTimer? .cancel ();
873
892
893
+ if (widget.contentTapHandlers != null ) {
894
+ final docOffset = _interactorOffsetToDocumentOffset (details.localPosition);
895
+ for (final handler in widget.contentTapHandlers! ) {
896
+ final result = handler.onPanStart (
897
+ DocumentTapDetails (
898
+ documentLayout: _docLayout,
899
+ layoutOffset: docOffset,
900
+ globalOffset: details.globalPosition,
901
+ ),
902
+ );
903
+ if (result == TapHandlingInstruction .halt) {
904
+ // The custom tap handler doesn't want us to react at all
905
+ // to the tap.
906
+ return ;
907
+ }
908
+ }
909
+ }
910
+
874
911
// TODO: to help the user drag handles instead of scrolling, try checking touch
875
912
// placement during onTapDown, and then pick that up here. I think the little
876
913
// bit of slop might be the problem.
@@ -957,6 +994,24 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
957
994
}
958
995
959
996
void _onPanUpdate (DragUpdateDetails details) {
997
+ if (widget.contentTapHandlers != null ) {
998
+ final docOffset = _interactorOffsetToDocumentOffset (details.localPosition);
999
+ for (final handler in widget.contentTapHandlers! ) {
1000
+ final result = handler.onPanUpdate (
1001
+ DocumentTapDetails (
1002
+ documentLayout: _docLayout,
1003
+ layoutOffset: docOffset,
1004
+ globalOffset: details.globalPosition,
1005
+ ),
1006
+ );
1007
+ if (result == TapHandlingInstruction .halt) {
1008
+ // The custom tap handler doesn't want us to react at all
1009
+ // to the tap.
1010
+ return ;
1011
+ }
1012
+ }
1013
+ }
1014
+
960
1015
_globalDragOffset = details.globalPosition;
961
1016
962
1017
_dragEndInInteractor = interactorBox.globalToLocal (details.globalPosition);
@@ -1003,6 +1058,7 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
1003
1058
const ClearComposingRegionRequest (),
1004
1059
]);
1005
1060
} else if (_dragHandleType == HandleType .upstream) {
1061
+ _controlsController! .handleBeingDragged.value = HandleType .upstream;
1006
1062
widget.editor.execute ([
1007
1063
ChangeSelectionRequest (
1008
1064
widget.selection.value! .copyWith (
@@ -1014,6 +1070,7 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
1014
1070
const ClearComposingRegionRequest (),
1015
1071
]);
1016
1072
} else if (_dragHandleType == HandleType .downstream) {
1073
+ _controlsController! .handleBeingDragged.value = HandleType .downstream;
1017
1074
widget.editor.execute ([
1018
1075
ChangeSelectionRequest (
1019
1076
widget.selection.value! .copyWith (
@@ -1028,9 +1085,28 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
1028
1085
}
1029
1086
1030
1087
void _onPanEnd (DragEndDetails details) {
1088
+ if (widget.contentTapHandlers != null ) {
1089
+ final docOffset = _interactorOffsetToDocumentOffset (details.localPosition);
1090
+ for (final handler in widget.contentTapHandlers! ) {
1091
+ final result = handler.onPanEnd (
1092
+ DocumentTapDetails (
1093
+ documentLayout: _docLayout,
1094
+ layoutOffset: docOffset,
1095
+ globalOffset: details.globalPosition,
1096
+ ),
1097
+ );
1098
+ if (result == TapHandlingInstruction .halt) {
1099
+ // The custom tap handler doesn't want us to react at all
1100
+ // to the tap.
1101
+ return ;
1102
+ }
1103
+ }
1104
+ }
1105
+
1031
1106
_controlsController!
1032
1107
..hideMagnifier ()
1033
- ..blinkCaret ();
1108
+ ..blinkCaret ()
1109
+ ..handleBeingDragged.value = null ;
1034
1110
1035
1111
if (_dragMode != null ) {
1036
1112
// The user was dragging a selection change in some way, either with handles
@@ -1040,9 +1116,21 @@ class _IosDocumentTouchInteractorState extends State<IosDocumentTouchInteractor>
1040
1116
}
1041
1117
1042
1118
void _onPanCancel () {
1119
+ if (widget.contentTapHandlers != null ) {
1120
+ for (final handler in widget.contentTapHandlers! ) {
1121
+ final result = handler.onPanCancel ();
1122
+ if (result == TapHandlingInstruction .halt) {
1123
+ // The custom tap handler doesn't want us to react at all
1124
+ // to the tap.
1125
+ return ;
1126
+ }
1127
+ }
1128
+ }
1129
+
1043
1130
if (_dragMode != null ) {
1044
1131
_onDragSelectionEnd ();
1045
1132
}
1133
+ _controlsController! .handleBeingDragged.value = null ;
1046
1134
}
1047
1135
1048
1136
void _onDragSelectionEnd () {
@@ -1888,6 +1976,8 @@ class SuperEditorIosHandlesDocumentLayerBuilder implements SuperEditorLayerBuild
1888
1976
return const ContentLayerProxyWidget (child: SizedBox ());
1889
1977
}
1890
1978
1979
+ final controlsController = SuperEditorIosControlsScope .rootOf (context);
1980
+
1891
1981
return IosHandlesDocumentLayer (
1892
1982
document: editContext.document,
1893
1983
documentLayout: editContext.documentLayout,
@@ -1898,13 +1988,13 @@ class SuperEditorIosHandlesDocumentLayerBuilder implements SuperEditorLayerBuild
1898
1988
const ClearComposingRegionRequest (),
1899
1989
]);
1900
1990
},
1901
- handleColor : handleColor ??
1902
- SuperEditorIosControlsScope . maybeRootOf (context) ? .handleColor ??
1903
- Theme .of (context).primaryColor,
1991
+ areSelectionHandlesAllowed : controlsController.areSelectionHandlesAllowed,
1992
+ handleBeingDragged : controlsController.handleBeingDragged,
1993
+ handleColor : handleColor ?? controlsController.handleColor ?? Theme .of (context).primaryColor,
1904
1994
caretWidth: caretWidth ?? 2 ,
1905
1995
handleBallDiameter: handleBallDiameter ?? defaultIosHandleBallDiameter,
1906
- shouldCaretBlink: SuperEditorIosControlsScope . rootOf (context) .shouldCaretBlink,
1907
- floatingCursorController: SuperEditorIosControlsScope . rootOf (context) .floatingCursorController,
1996
+ shouldCaretBlink: controlsController .shouldCaretBlink,
1997
+ floatingCursorController: controlsController .floatingCursorController,
1908
1998
);
1909
1999
}
1910
2000
}
0 commit comments