Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4abe6fda
Unverified
Commit
4abe6fda
authored
Oct 17, 2022
by
Renzo Olivares
Committed by
GitHub
Oct 17, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland "Single tap on the previous selection should toggle the toolbar on iOS #108913" (#111995)
parent
57e577a5
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
486 additions
and
37 deletions
+486
-37
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+0
-1
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+0
-1
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+11
-8
text_selection.dart
packages/flutter/lib/src/widgets/text_selection.dart
+48
-2
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+169
-11
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+223
-13
text_selection_test.dart
packages/flutter/test/widgets/text_selection_test.dart
+35
-1
No files found.
packages/flutter/lib/src/cupertino/text_field.dart
View file @
4abe6fda
...
...
@@ -102,7 +102,6 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
@override
void
onSingleTapUp
(
TapUpDetails
details
)
{
editableText
.
hideToolbar
();
// Because TextSelectionGestureDetector listens to taps that happen on
// widgets in front of it, tapping the clear button will also trigger
// this handler. If the clear button widget recognizes the up event,
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
4abe6fda
...
...
@@ -103,7 +103,6 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
@override
void
onSingleTapUp
(
TapUpDetails
details
)
{
editableText
.
hideToolbar
();
super
.
onSingleTapUp
(
details
);
_state
.
_requestKeyboard
();
_state
.
widget
.
onTap
?.
call
();
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
4abe6fda
...
...
@@ -2724,8 +2724,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_scribbleCacheKey
=
null
;
}
void
_createSelectionOverlay
()
{
_
selectionOverlay
=
TextSelectionOverlay
(
TextSelectionOverlay
_createSelectionOverlay
()
{
final
TextSelectionOverlay
selectionOverlay
=
TextSelectionOverlay
(
clipboardStatus:
_clipboardStatus
,
context:
context
,
value:
_value
,
...
...
@@ -2740,6 +2740,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
onSelectionHandleTapped:
widget
.
onSelectionHandleTapped
,
magnifierConfiguration:
widget
.
magnifierConfiguration
,
);
return
selectionOverlay
;
}
@pragma
(
'vm:notify-debugger-on-exception'
)
...
...
@@ -2780,7 +2782,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay
=
null
;
}
else
{
if
(
_selectionOverlay
==
null
)
{
_createSelectionOverlay
();
_
selectionOverlay
=
_
createSelectionOverlay
();
}
else
{
_selectionOverlay
!.
update
(
_value
);
}
...
...
@@ -3266,7 +3268,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if
(
value
==
textEditingValue
)
{
if
(!
widget
.
focusNode
.
hasFocus
)
{
widget
.
focusNode
.
requestFocus
();
_createSelectionOverlay
();
_
selectionOverlay
=
_
createSelectionOverlay
();
}
return
;
}
...
...
@@ -3317,10 +3319,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
/// Toggles the visibility of the toolbar.
void
toggleToolbar
()
{
assert
(
_selectionOverlay
!=
null
);
if
(
_selectionOverlay
!.
toolbarIsVisible
)
{
hideToolbar
();
void
toggleToolbar
([
bool
hideHandles
=
true
])
{
final
TextSelectionOverlay
selectionOverlay
=
_selectionOverlay
??=
_createSelectionOverlay
();
if
(
selectionOverlay
.
toolbarIsVisible
)
{
hideToolbar
(
hideHandles
);
}
else
{
showToolbar
();
}
...
...
packages/flutter/lib/src/widgets/text_selection.dart
View file @
4abe6fda
...
...
@@ -1635,6 +1635,26 @@ class TextSelectionGestureDetectorBuilder {
&&
renderEditable
.
selection
!.
end
>=
textPosition
.
offset
;
}
bool
_positionWasOnSelectionExclusive
(
TextPosition
textPosition
)
{
final
TextSelection
?
selection
=
renderEditable
.
selection
;
if
(
selection
==
null
)
{
return
false
;
}
return
selection
.
start
<
textPosition
.
offset
&&
selection
.
end
>
textPosition
.
offset
;
}
bool
_positionWasOnSelectionInclusive
(
TextPosition
textPosition
)
{
final
TextSelection
?
selection
=
renderEditable
.
selection
;
if
(
selection
==
null
)
{
return
false
;
}
return
selection
.
start
<=
textPosition
.
offset
&&
selection
.
end
>=
textPosition
.
offset
;
}
// Expand the selection to the given global position.
//
// Either base or extent will be moved to the last tapped position, whichever
...
...
@@ -1879,6 +1899,7 @@ class TextSelectionGestureDetectorBuilder {
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
macOS
:
case
TargetPlatform
.
windows
:
editableText
.
hideToolbar
();
// On desktop platforms the selection is set on tap down.
if
(
_isShiftTapping
)
{
_isShiftTapping
=
false
;
...
...
@@ -1886,6 +1907,7 @@ class TextSelectionGestureDetectorBuilder {
break
;
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
editableText
.
hideToolbar
();
if
(
isShiftPressedValid
)
{
_isShiftTapping
=
true
;
_extendSelection
(
details
.
globalPosition
,
SelectionChangedCause
.
tap
);
...
...
@@ -1918,8 +1940,32 @@ class TextSelectionGestureDetectorBuilder {
break
;
case
PointerDeviceKind
.
touch
:
case
PointerDeviceKind
.
unknown
:
// On iOS/iPadOS a touch tap places the cursor at the edge of the word.
// Toggle the toolbar if the `previousSelection` is collapsed, the tap is on the selection, the
// TextAffinity remains the same, and the editable is focused. The TextAffinity is important when the
// cursor is on the boundary of a line wrap, if the affinity is different (i.e. it is downstream), the
// selection should move to the following line and not toggle the toolbar.
//
// Toggle the toolbar when the tap is exclusively within the bounds of a non-collapsed `previousSelection`,
// and the editable is focused.
//
// Selects the word edge closest to the tap when the editable is not focused, or if the tap was neither exclusively
// or inclusively on `previousSelection`. If the selection remains the same after selecting the word edge, then we
// toggle the toolbar. If the selection changes then we hide the toolbar.
final
TextSelection
previousSelection
=
renderEditable
.
selection
??
editableText
.
textEditingValue
.
selection
;
final
TextPosition
textPosition
=
renderEditable
.
getPositionForPoint
(
details
.
globalPosition
);
final
bool
isAffinityTheSame
=
textPosition
.
affinity
==
previousSelection
.
affinity
;
if
(((
_positionWasOnSelectionExclusive
(
textPosition
)
&&
!
previousSelection
.
isCollapsed
)
||
(
_positionWasOnSelectionInclusive
(
textPosition
)
&&
previousSelection
.
isCollapsed
&&
isAffinityTheSame
))
&&
renderEditable
.
hasFocus
)
{
editableText
.
toggleToolbar
(
false
);
}
else
{
renderEditable
.
selectWordEdge
(
cause:
SelectionChangedCause
.
tap
);
if
(
previousSelection
==
editableText
.
textEditingValue
.
selection
&&
renderEditable
.
hasFocus
)
{
editableText
.
toggleToolbar
(
false
);
}
else
{
editableText
.
hideToolbar
(
false
);
}
}
break
;
}
break
;
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
4abe6fda
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/text_field_test.dart
View file @
4abe6fda
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/text_selection_test.dart
View file @
4abe6fda
...
...
@@ -570,6 +570,38 @@ void main() {
}
},
variant:
TargetPlatformVariant
.
all
());
testWidgets
(
'test TextSelectionGestureDetectorBuilder toggles toolbar on single tap on previous selection iOS'
,
(
WidgetTester
tester
)
async
{
await
pumpTextSelectionGestureDetectorBuilder
(
tester
);
final
FakeEditableTextState
state
=
tester
.
state
(
find
.
byType
(
FakeEditableText
));
final
FakeRenderEditable
renderEditable
=
tester
.
renderObject
(
find
.
byType
(
FakeEditable
));
expect
(
state
.
showToolbarCalled
,
isFalse
);
expect
(
state
.
toggleToolbarCalled
,
isFalse
);
renderEditable
.
selection
=
const
TextSelection
(
baseOffset:
2
,
extentOffset:
6
);
renderEditable
.
hasFocus
=
true
;
final
TestGesture
gesture
=
await
tester
.
startGesture
(
const
Offset
(
25.0
,
200.0
),
pointer:
0
,
);
await
gesture
.
up
();
await
tester
.
pumpAndSettle
();
switch
(
defaultTargetPlatform
)
{
case
TargetPlatform
.
iOS
:
expect
(
renderEditable
.
selectWordEdgeCalled
,
isFalse
);
expect
(
state
.
toggleToolbarCalled
,
isTrue
);
break
;
case
TargetPlatform
.
macOS
:
case
TargetPlatform
.
android
:
case
TargetPlatform
.
fuchsia
:
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
windows
:
expect
(
renderEditable
.
selectPositionAtCalled
,
isTrue
);
break
;
}
},
variant:
TargetPlatformVariant
.
all
());
testWidgets
(
'test TextSelectionGestureDetectorBuilder double tap'
,
(
WidgetTester
tester
)
async
{
await
pumpTextSelectionGestureDetectorBuilder
(
tester
);
final
TestGesture
gesture
=
await
tester
.
startGesture
(
...
...
@@ -1519,6 +1551,7 @@ class FakeEditableText extends EditableText {
class
FakeEditableTextState
extends
EditableTextState
{
final
GlobalKey
_editableKey
=
GlobalKey
();
bool
showToolbarCalled
=
false
;
bool
toggleToolbarCalled
=
false
;
@override
RenderEditable
get
renderEditable
=>
_editableKey
.
currentContext
!.
findRenderObject
()!
as
RenderEditable
;
...
...
@@ -1530,7 +1563,8 @@ class FakeEditableTextState extends EditableTextState {
}
@override
void
toggleToolbar
()
{
void
toggleToolbar
([
bool
hideHandles
=
true
])
{
toggleToolbarCalled
=
true
;
return
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment