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
ef5abcc6
Unverified
Commit
ef5abcc6
authored
May 14, 2019
by
Mouad Debbar
Committed by
GitHub
May 14, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Show/hide toolbar and handles based on device kind (#29683)" (#32702)
This reverts commit
18ca3754
.
parent
7ab111ea
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
92 additions
and
686 deletions
+92
-686
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+6
-49
multitap.dart
packages/flutter/lib/src/gestures/multitap.dart
+2
-15
recognizer.dart
packages/flutter/lib/src/gestures/recognizer.dart
+5
-31
tap.dart
packages/flutter/lib/src/gestures/tap.dart
+7
-17
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+5
-53
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+3
-22
text_selection.dart
packages/flutter/lib/src/widgets/text_selection.dart
+16
-24
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+0
-189
debug_test.dart
packages/flutter/test/gestures/debug_test.dart
+1
-1
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+2
-280
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+45
-5
No files found.
packages/flutter/lib/src/cupertino/text_field.dart
View file @
ef5abcc6
...
...
@@ -469,12 +469,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
FocusNode
_focusNode
;
FocusNode
get
_effectiveFocusNode
=>
widget
.
focusNode
??
(
_focusNode
??=
FocusNode
());
// The selection overlay should only be shown when the user is interacting
// through a touch screen (via either a finger or a stylus). A mouse shouldn't
// trigger the selection overlay.
// For backwards-compatibility, we treat a null kind the same as touch.
bool
_shouldShowSelectionToolbar
=
true
;
@override
void
initState
()
{
super
.
initState
();
...
...
@@ -507,26 +501,14 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
super
.
dispose
();
}
EditableTextState
get
_editableText
=>
_editableTextKey
.
currentState
;
void
_requestKeyboard
()
{
_editableText
?.
requestKeyboard
();
_editableText
Key
.
currentState
?.
requestKeyboard
();
}
RenderEditable
get
_renderEditable
=>
_editableText
.
renderEditable
;
RenderEditable
get
_renderEditable
=>
_editableText
Key
.
currentState
.
renderEditable
;
void
_handleTapDown
(
TapDownDetails
details
)
{
_renderEditable
.
handleTapDown
(
details
);
// The selection overlay should only be shown when the user is interacting
// through a touch screen (via either a finger or a stylus). A mouse shouldn't
// trigger the selection overlay.
// For backwards-compatibility, we treat a null kind the same as touch.
final
PointerDeviceKind
kind
=
details
.
kind
;
_shouldShowSelectionToolbar
=
kind
==
null
||
kind
==
PointerDeviceKind
.
touch
||
kind
==
PointerDeviceKind
.
stylus
;
}
void
_handleForcePressStarted
(
ForcePressDetails
details
)
{
...
...
@@ -541,8 +523,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
from:
details
.
globalPosition
,
cause:
SelectionChangedCause
.
forcePress
,
);
if
(
_shouldShowSelectionToolbar
)
_editableText
.
showToolbar
();
_editableTextKey
.
currentState
.
showToolbar
();
}
void
_handleSingleTapUp
(
TapUpDetails
details
)
{
...
...
@@ -565,33 +546,12 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
}
void
_handleSingleLongTapEnd
(
LongPressEndDetails
details
)
{
if
(
_shouldShowSelectionToolbar
)
_editableText
.
showToolbar
();
_editableTextKey
.
currentState
.
showToolbar
();
}
void
_handleDoubleTapDown
(
TapDownDetails
details
)
{
_renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
tap
);
if
(
_shouldShowSelectionToolbar
)
_editableText
.
showToolbar
();
}
bool
_shouldShowSelectionHandles
(
SelectionChangedCause
cause
)
{
// When the text field is activated by something that doesn't trigger the
// selection overlay, we shouldn't show the handles either.
if
(!
_shouldShowSelectionToolbar
)
return
false
;
// On iOS, we don't show handles when the selection is collapsed.
if
(
_effectiveController
.
selection
.
isCollapsed
)
return
false
;
if
(
cause
==
SelectionChangedCause
.
keyboard
)
return
false
;
if
(
_effectiveController
.
text
.
isNotEmpty
)
return
true
;
return
false
;
_editableTextKey
.
currentState
.
showToolbar
();
}
void
_handleMouseDragSelectionStart
(
DragStartDetails
details
)
{
...
...
@@ -618,10 +578,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
void
_handleSelectionChanged
(
TextSelection
selection
,
SelectionChangedCause
cause
)
{
if
(
cause
==
SelectionChangedCause
.
longPress
)
{
_editableText
?.
bringIntoView
(
selection
.
base
);
}
if
(
_shouldShowSelectionHandles
(
cause
))
{
_editableText
?.
showHandles
();
_editableTextKey
.
currentState
?.
bringIntoView
(
selection
.
base
);
}
}
...
...
packages/flutter/lib/src/gestures/multitap.dart
View file @
ef5abcc6
...
...
@@ -397,12 +397,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
longTapDelay:
longTapDelay
,
);
if
(
onTapDown
!=
null
)
invokeCallback
<
void
>(
'onTapDown'
,
()
{
onTapDown
(
event
.
pointer
,
TapDownDetails
(
globalPosition:
event
.
position
,
kind:
event
.
kind
,
));
});
invokeCallback
<
void
>(
'onTapDown'
,
()
=>
onTapDown
(
event
.
pointer
,
TapDownDetails
(
globalPosition:
event
.
position
)));
}
@override
...
...
@@ -437,15 +432,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
void
_dispatchLongTap
(
int
pointer
,
Offset
lastPosition
)
{
assert
(
_gestureMap
.
containsKey
(
pointer
));
if
(
onLongTapDown
!=
null
)
invokeCallback
<
void
>(
'onLongTapDown'
,
()
{
onLongTapDown
(
pointer
,
TapDownDetails
(
globalPosition:
lastPosition
,
kind:
getKindForPointer
(
pointer
),
),
);
});
invokeCallback
<
void
>(
'onLongTapDown'
,
()
=>
onLongTapDown
(
pointer
,
TapDownDetails
(
globalPosition:
lastPosition
)));
}
@override
...
...
packages/flutter/lib/src/gestures/recognizer.dart
View file @
ef5abcc6
...
...
@@ -64,7 +64,7 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
/// by providing the optional [kind] argument. If [kind] is null,
/// the recognizer will accept pointer events from all device kinds.
/// {@endtemplate}
GestureRecognizer
({
this
.
debugOwner
,
PointerDeviceKind
kind
})
:
_kind
Filter
=
kind
;
GestureRecognizer
({
this
.
debugOwner
,
PointerDeviceKind
kind
})
:
_kind
=
kind
;
/// The recognizer's owner.
///
...
...
@@ -74,11 +74,7 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
/// The kind of device that's allowed to be recognized. If null, events from
/// all device kinds will be tracked and recognized.
final
PointerDeviceKind
_kindFilter
;
/// Holds a mapping between pointer IDs and the kind of devices they are
/// coming from.
final
Map
<
int
,
PointerDeviceKind
>
_pointerToKind
=
<
int
,
PointerDeviceKind
>{};
final
PointerDeviceKind
_kind
;
/// Registers a new pointer that might be relevant to this gesture
/// detector.
...
...
@@ -96,7 +92,6 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
/// This method is called for each and all pointers being added. In
/// most cases, you want to override [addAllowedPointer] instead.
void
addPointer
(
PointerDownEvent
event
)
{
_pointerToKind
[
event
.
pointer
]
=
event
.
kind
;
if
(
isPointerAllowed
(
event
))
{
addAllowedPointer
(
event
);
}
else
{
...
...
@@ -128,17 +123,7 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
bool
isPointerAllowed
(
PointerDownEvent
event
)
{
// Currently, it only checks for device kind. But in the future we could check
// for other things e.g. mouse button.
return
_kindFilter
==
null
||
_kindFilter
==
event
.
kind
;
}
/// For a given pointer ID, returns the device kind associated with it.
///
/// The pointer ID is expected to be a valid one i.e. an event was received
/// with that pointer ID.
@protected
PointerDeviceKind
getKindForPointer
(
int
pointer
)
{
assert
(
_pointerToKind
.
containsKey
(
pointer
));
return
_pointerToKind
[
pointer
];
return
_kind
==
null
||
_kind
==
event
.
kind
;
}
/// Releases any resources used by the object.
...
...
@@ -426,7 +411,7 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
primaryPointer
=
event
.
pointer
;
initialPosition
=
event
.
position
;
if
(
deadline
!=
null
)
_timer
=
Timer
(
deadline
,
()
=>
didExceedDeadlineWithEvent
(
event
)
);
_timer
=
Timer
(
deadline
,
didExceedDeadline
);
}
}
...
...
@@ -459,23 +444,12 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
/// Override to be notified when [deadline] is exceeded.
///
/// You must override this method or [didExceedDeadlineWithEvent] if you
/// supply a [deadline].
/// You must override this method if you supply a [deadline].
@protected
void
didExceedDeadline
()
{
assert
(
deadline
==
null
);
}
/// Same as [didExceedDeadline] but receives the [event] that initiated the
/// gesture.
///
/// You must override this method or [didExceedDeadline] if you supply a
/// [deadline].
@protected
void
didExceedDeadlineWithEvent
(
PointerDownEvent
event
)
{
didExceedDeadline
();
}
@override
void
acceptGesture
(
int
pointer
)
{
_gestureAccepted
=
true
;
...
...
packages/flutter/lib/src/gestures/tap.dart
View file @
ef5abcc6
...
...
@@ -19,16 +19,11 @@ class TapDownDetails {
/// Creates details for a [GestureTapDownCallback].
///
/// The [globalPosition] argument must not be null.
TapDownDetails
({
this
.
globalPosition
=
Offset
.
zero
,
this
.
kind
,
})
:
assert
(
globalPosition
!=
null
);
TapDownDetails
({
this
.
globalPosition
=
Offset
.
zero
})
:
assert
(
globalPosition
!=
null
);
/// The global position at which the pointer contacted the screen.
final
Offset
globalPosition
;
/// The kind of the device that initiated the event.
final
PointerDeviceKind
kind
;
}
/// Signature for when a pointer that might cause a tap has contacted the
...
...
@@ -203,15 +198,15 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
}
@override
void
didExceedDeadline
WithEvent
(
PointerDownEvent
event
)
{
_checkDown
(
event
.
pointer
);
void
didExceedDeadline
(
)
{
_checkDown
();
}
@override
void
acceptGesture
(
int
pointer
)
{
super
.
acceptGesture
(
pointer
);
if
(
pointer
==
primaryPointer
)
{
_checkDown
(
pointer
);
_checkDown
();
_wonArenaForPrimaryPointer
=
true
;
_checkUp
();
}
...
...
@@ -229,15 +224,10 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
}
}
void
_checkDown
(
int
pointer
)
{
void
_checkDown
()
{
if
(!
_sentTapDown
)
{
if
(
onTapDown
!=
null
)
invokeCallback
<
void
>(
'onTapDown'
,
()
{
onTapDown
(
TapDownDetails
(
globalPosition:
initialPosition
,
kind:
getKindForPointer
(
pointer
),
));
});
invokeCallback
<
void
>(
'onTapDown'
,
()
{
onTapDown
(
TapDownDetails
(
globalPosition:
initialPosition
));
});
_sentTapDown
=
true
;
}
}
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
ef5abcc6
...
...
@@ -513,8 +513,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
&&
widget
.
decoration
!=
null
&&
widget
.
decoration
.
counterText
==
null
;
bool
_shouldShowSelectionToolbar
=
true
;
InputDecoration
_getEffectiveDecoration
()
{
final
MaterialLocalizations
localizations
=
MaterialLocalizations
.
of
(
context
);
final
ThemeData
themeData
=
Theme
.
of
(
context
);
...
...
@@ -607,41 +605,17 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
super
.
dispose
();
}
EditableTextState
get
_editableText
=>
_editableTextKey
.
currentState
;
void
_requestKeyboard
()
{
_editableText
?.
requestKeyboard
();
}
bool
_shouldShowSelectionHandles
(
SelectionChangedCause
cause
)
{
// When the text field is activated by something that doesn't trigger the
// selection overlay, we shouldn't show the handles either.
if
(!
_shouldShowSelectionToolbar
)
return
false
;
if
(
cause
==
SelectionChangedCause
.
keyboard
)
return
false
;
if
(
cause
==
SelectionChangedCause
.
longPress
)
return
true
;
if
(
_effectiveController
.
text
.
isNotEmpty
)
return
true
;
return
false
;
_editableTextKey
.
currentState
?.
requestKeyboard
();
}
void
_handleSelectionChanged
(
TextSelection
selection
,
SelectionChangedCause
cause
)
{
// iOS cursor doesn't move via a selection handle. The scroll happens
// directly from new text selection changes.
if
(
_shouldShowSelectionHandles
(
cause
))
{
_editableText
?.
showHandles
();
}
switch
(
Theme
.
of
(
context
).
platform
)
{
case
TargetPlatform
.
iOS
:
if
(
cause
==
SelectionChangedCause
.
longPress
)
{
_editableText
?.
bringIntoView
(
selection
.
base
);
_editableText
Key
.
currentState
?.
bringIntoView
(
selection
.
base
);
}
return
;
case
TargetPlatform
.
android
:
...
...
@@ -650,13 +624,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
}
}
/// Toggle the toolbar when a selection handle is tapped.
void
_handleSelectionHandleTapped
()
{
if
(
_effectiveController
.
selection
.
isCollapsed
)
{
_editableText
.
toggleToolbar
();
}
}
InteractiveInkFeature
_createInkFeature
(
Offset
globalPosition
)
{
final
MaterialInkController
inkController
=
Material
.
of
(
context
);
final
ThemeData
themeData
=
Theme
.
of
(
context
);
...
...
@@ -696,16 +663,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
void
_handleTapDown
(
TapDownDetails
details
)
{
_renderEditable
.
handleTapDown
(
details
);
_startSplash
(
details
.
globalPosition
);
// The selection overlay should only be shown when the user is interacting
// through a touch screen (via either a finger or a stylus). A mouse shouldn't
// trigger the selection overlay.
// For backwards-compatibility, we treat a null kind the same as touch.
final
PointerDeviceKind
kind
=
details
.
kind
;
_shouldShowSelectionToolbar
=
kind
==
null
||
kind
==
PointerDeviceKind
.
touch
||
kind
==
PointerDeviceKind
.
stylus
;
}
void
_handleForcePressStarted
(
ForcePressDetails
details
)
{
...
...
@@ -714,8 +671,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
from:
details
.
globalPosition
,
cause:
SelectionChangedCause
.
forcePress
,
);
if
(
_shouldShowSelectionToolbar
)
_editableTextKey
.
currentState
.
showToolbar
();
_editableTextKey
.
currentState
.
showToolbar
();
}
}
...
...
@@ -782,16 +738,13 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
}
void
_handleSingleLongTapEnd
(
LongPressEndDetails
details
)
{
print
(
'long tap end'
);
if
(
_shouldShowSelectionToolbar
)
_editableTextKey
.
currentState
.
showToolbar
();
_editableTextKey
.
currentState
.
showToolbar
();
}
void
_handleDoubleTapDown
(
TapDownDetails
details
)
{
if
(
widget
.
selectionEnabled
)
{
_renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
doubleTap
);
if
(
_shouldShowSelectionToolbar
)
_editableTextKey
.
currentState
.
showToolbar
();
_editableTextKey
.
currentState
.
showToolbar
();
}
}
...
...
@@ -931,7 +884,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
onSelectionChanged:
_handleSelectionChanged
,
onEditingComplete:
widget
.
onEditingComplete
,
onSubmitted:
widget
.
onSubmitted
,
onSelectionHandleTapped:
_handleSelectionHandleTapped
,
inputFormatters:
formatters
,
rendererIgnoresPointer:
true
,
cursorWidth:
widget
.
cursorWidth
,
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
ef5abcc6
...
...
@@ -290,7 +290,6 @@ class EditableText extends StatefulWidget {
this
.
onEditingComplete
,
this
.
onSubmitted
,
this
.
onSelectionChanged
,
this
.
onSelectionHandleTapped
,
List
<
TextInputFormatter
>
inputFormatters
,
this
.
rendererIgnoresPointer
=
false
,
this
.
cursorWidth
=
2.0
,
...
...
@@ -646,9 +645,6 @@ class EditableText extends StatefulWidget {
/// location).
final
SelectionChangedCallback
onSelectionChanged
;
/// {@macro flutter.widgets.textSelection.onSelectionHandleTapped}
final
VoidCallback
onSelectionHandleTapped
;
/// {@template flutter.widgets.editableText.inputFormatters}
/// Optional input validation and formatting overrides.
///
...
...
@@ -1139,9 +1135,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
selectionControls:
widget
.
selectionControls
,
selectionDelegate:
this
,
dragStartBehavior:
widget
.
dragStartBehavior
,
onSelectionHandleTapped:
widget
.
onSelectionHandleTapped
,
);
final
bool
longPress
=
cause
==
SelectionChangedCause
.
longPress
;
if
(
cause
!=
SelectionChangedCause
.
keyboard
&&
(
_value
.
text
.
isNotEmpty
||
longPress
))
_selectionOverlay
.
showHandles
();
if
(
widget
.
onSelectionChanged
!=
null
)
widget
.
onSelectionChanged
(
selection
,
cause
);
}
...
...
@@ -1384,22 +1381,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay
?.
hide
();
}
/// Toggles the visibility of the toolbar.
void
toggleToolbar
()
{
assert
(
_selectionOverlay
!=
null
);
if
(
_selectionOverlay
.
toolbarIsVisible
)
{
hideToolbar
();
}
else
{
showToolbar
();
}
}
/// Shows the handles at the location of the current selection.
void
showHandles
()
{
assert
(
_selectionOverlay
!=
null
);
_selectionOverlay
.
showHandles
();
}
VoidCallback
_semanticsOnCopy
(
TextSelectionControls
controls
)
{
return
widget
.
selectionEnabled
&&
_hasFocus
&&
controls
?.
canCopy
(
this
)
==
true
?
()
=>
controls
.
handleCopy
(
this
)
...
...
packages/flutter/lib/src/widgets/text_selection.dart
View file @
ef5abcc6
...
...
@@ -263,7 +263,6 @@ class TextSelectionOverlay {
this
.
selectionControls
,
this
.
selectionDelegate
,
this
.
dragStartBehavior
=
DragStartBehavior
.
start
,
this
.
onSelectionHandleTapped
,
})
:
assert
(
value
!=
null
),
assert
(
context
!=
null
),
_value
=
value
{
...
...
@@ -317,14 +316,6 @@ class TextSelectionOverlay {
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
final
DragStartBehavior
dragStartBehavior
;
/// {@template flutter.widgets.textSelection.onSelectionHandleTapped}
/// A callback that's invoked when a selection handle is tapped.
///
/// Both regular taps and long presses invoke this callback, but a drag
/// gesture won't.
/// {@endtemplate}
final
VoidCallback
onSelectionHandleTapped
;
/// Controls the fade-in and fade-out animations for the toolbar and handles.
static
const
Duration
fadeDuration
=
Duration
(
milliseconds:
150
);
...
...
@@ -402,26 +393,17 @@ class TextSelectionOverlay {
/// Whether the toolbar is currently visible.
bool
get
toolbarIsVisible
=>
_toolbar
!=
null
;
/// Hides the
entire overlay including the toolbar and the handles
.
/// Hides the
overlay
.
void
hide
()
{
if
(
_handles
!=
null
)
{
_handles
[
0
].
remove
();
_handles
[
1
].
remove
();
_handles
=
null
;
}
if
(
_toolbar
!=
null
)
{
hideToolbar
();
}
}
_toolbar
?.
remove
();
_toolbar
=
null
;
/// Hides the toolbar part of the overlay.
///
/// To hide the whole overlay, see [hide].
void
hideToolbar
()
{
assert
(
_toolbar
!=
null
);
_toolbarController
.
stop
();
_toolbar
.
remove
();
_toolbar
=
null
;
}
/// Final cleanup.
...
...
@@ -436,7 +418,7 @@ class TextSelectionOverlay {
return
Container
();
// hide the second handle when collapsed
return
_TextSelectionHandleOverlay
(
onSelectionHandleChanged:
(
TextSelection
newSelection
)
{
_handleSelectionHandleChanged
(
newSelection
,
position
);
},
onSelectionHandleTapped:
on
SelectionHandleTapped
,
onSelectionHandleTapped:
_handle
SelectionHandleTapped
,
layerLink:
layerLink
,
renderObject:
renderObject
,
selection:
_selection
,
...
...
@@ -494,6 +476,17 @@ class TextSelectionOverlay {
selectionDelegate
.
textEditingValue
=
_value
.
copyWith
(
selection:
newSelection
,
composing:
TextRange
.
empty
);
selectionDelegate
.
bringIntoView
(
textPosition
);
}
void
_handleSelectionHandleTapped
()
{
if
(
_value
.
selection
.
isCollapsed
)
{
if
(
_toolbar
!=
null
)
{
_toolbar
?.
remove
();
_toolbar
=
null
;
}
else
{
showToolbar
();
}
}
}
}
/// This widget represents a single draggable text selection handle.
...
...
@@ -609,8 +602,7 @@ class _TextSelectionHandleOverlayState
}
void
_handleTap
()
{
if
(
widget
.
onSelectionHandleTapped
!=
null
)
widget
.
onSelectionHandleTapped
();
widget
.
onSelectionHandleTapped
();
}
@override
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
ef5abcc6
...
...
@@ -2008,195 +2008,6 @@ void main() {
await
gesture
.
removePointer
();
});
testWidgets
(
'Tap does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
// Tap to trigger the text field.
await
tester
.
tap
(
find
.
byType
(
CupertinoTextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
});
testWidgets
(
'Long press shows toolbar but not handles'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
// Long press to trigger the text field.
await
tester
.
longPress
(
find
.
byType
(
CupertinoTextField
));
await
tester
.
pump
();
// A long press in Cupertino should position the cursor without any selection.
expect
(
controller
.
selection
.
isCollapsed
,
isTrue
);
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
});
testWidgets
(
'Double tap shows handles and toolbar if selection is not collapsed'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
final
Offset
hPos
=
textOffsetToPosition
(
tester
,
9
);
// Position of 'h'.
// Double tap on 'h' to select 'ghi'.
await
tester
.
tapAt
(
hPos
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
tester
.
tapAt
(
hPos
);
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
},
);
testWidgets
(
'Double tap shows toolbar but not handles if selection is collapsed'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
final
Offset
textEndPos
=
textOffsetToPosition
(
tester
,
11
);
// Position at the end of text.
// Double tap to place the cursor at the end.
await
tester
.
tapAt
(
textEndPos
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
tester
.
tapAt
(
textEndPos
);
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
},
);
testWidgets
(
'Mouse long press does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
// Long press to trigger the text field.
final
Offset
textFieldPos
=
tester
.
getCenter
(
find
.
byType
(
CupertinoTextField
));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
textFieldPos
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
await
gesture
.
up
();
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
},
);
testWidgets
(
'Mouse double tap does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
CupertinoApp
(
home:
Center
(
child:
CupertinoTextField
(
controller:
controller
),
),
),
);
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
// Double tap at the end of text.
final
Offset
textEndPos
=
textOffsetToPosition
(
tester
,
11
);
// Position at the end of text.
TestGesture
gesture
=
await
tester
.
startGesture
(
textEndPos
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
gesture
.
up
();
await
tester
.
pump
();
await
gesture
.
down
(
textEndPos
);
await
tester
.
pump
();
await
gesture
.
up
();
await
tester
.
pump
();
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
final
Offset
hPos
=
textOffsetToPosition
(
tester
,
9
);
// Position of 'h'.
// Double tap on 'h' to select 'ghi'.
gesture
=
await
tester
.
startGesture
(
hPos
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
gesture
.
up
();
await
tester
.
pump
();
await
gesture
.
down
(
hPos
);
await
tester
.
pump
();
await
gesture
.
up
();
await
tester
.
pump
();
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
},
);
testWidgets
(
'text field respects theme'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/gestures/debug_test.dart
View file @
ef5abcc6
...
...
@@ -151,7 +151,7 @@ void main() {
expect
(
tap
.
toString
(),
equalsIgnoringHashCodes
(
'TapGestureRecognizer#00000(state: ready)'
));
const
PointerEvent
event
=
PointerDownEvent
(
pointer:
1
,
position:
Offset
(
10.0
,
10.0
));
tap
.
addPointer
(
event
);
tap
.
didExceedDeadline
WithEvent
(
event
);
tap
.
didExceedDeadline
(
);
expect
(
tap
.
toString
(),
equalsIgnoringHashCodes
(
'TapGestureRecognizer#00000(state: possible, sent tap down)'
));
});
}
packages/flutter/test/material/text_field_test.dart
View file @
ef5abcc6
...
...
@@ -5909,9 +5909,8 @@ void main() {
),
);
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
final
RenderEditable
renderEditable
=
state
.
renderEditable
;
final
RenderEditable
renderEditable
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
)).
renderEditable
;
await
tester
.
tapAt
(
const
Offset
(
20
,
10
));
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
...
...
@@ -5962,281 +5961,4 @@ void main() {
debugDefaultTargetPlatformOverride
=
null
;
});
testWidgets
(
'Tap shows handles but not toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Tap to trigger the text field.
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
});
testWidgets
(
'Tap in empty text field does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Tap to trigger the text field.
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
},
);
testWidgets
(
'Long press shows handles and toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Long press to trigger the text field.
await
tester
.
longPress
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
});
testWidgets
(
'Long press in empty text field shows handles and toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Tap to trigger the text field.
await
tester
.
longPress
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
},
);
testWidgets
(
'Double tap shows handles and toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Double tap to trigger the text field.
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
});
testWidgets
(
'Double tap in empty text field shows toolbar but not handles'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Double tap to trigger the text field.
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
},
);
testWidgets
(
'Mouse tap does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Long press to trigger the text field.
final
Offset
textFieldPos
=
tester
.
getCenter
(
find
.
byType
(
TextField
));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
textFieldPos
,
pointer:
7
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
();
await
gesture
.
up
();
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
},
);
testWidgets
(
'Mouse long press does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Long press to trigger the text field.
final
Offset
textFieldPos
=
tester
.
getCenter
(
find
.
byType
(
TextField
));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
textFieldPos
,
pointer:
7
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
(
const
Duration
(
seconds:
2
));
await
gesture
.
up
();
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
},
);
testWidgets
(
'Mouse double tap does not show handles nor toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Double tap to trigger the text field.
final
Offset
textFieldPos
=
tester
.
getCenter
(
find
.
byType
(
TextField
));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
textFieldPos
,
pointer:
7
,
kind:
PointerDeviceKind
.
mouse
,
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
gesture
.
up
();
await
tester
.
pump
();
await
gesture
.
down
(
textFieldPos
);
await
tester
.
pump
();
await
gesture
.
up
();
await
tester
.
pump
();
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
},
);
testWidgets
(
'Tapping selection handles toggles the toolbar'
,
(
WidgetTester
tester
)
async
{
final
TextEditingController
controller
=
TextEditingController
(
text:
'abc def ghi'
,
);
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Material
(
child:
TextField
(
controller:
controller
),
),
),
);
// Tap to position the cursor and show the selection handles.
final
Offset
ePos
=
textOffsetToPosition
(
tester
,
5
);
// Index of 'e'.
await
tester
.
tapAt
(
ePos
,
pointer:
7
);
final
EditableTextState
editableText
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
expect
(
editableText
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
final
RenderEditable
renderEditable
=
findRenderEditable
(
tester
);
final
List
<
TextSelectionPoint
>
endpoints
=
globalize
(
renderEditable
.
getEndpointsForSelection
(
controller
.
selection
),
renderEditable
,
);
expect
(
endpoints
.
length
,
1
);
// Tap the handle to show the toolbar.
final
Offset
handlePos
=
endpoints
[
0
].
point
+
const
Offset
(
0.0
,
1.0
);
await
tester
.
tapAt
(
handlePos
,
pointer:
7
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isTrue
);
// Tap the handle again to hide the toolbar.
await
tester
.
tapAt
(
handlePos
,
pointer:
7
);
expect
(
editableText
.
selectionOverlay
.
toolbarIsVisible
,
isFalse
);
});
}
packages/flutter/test/widgets/editable_text_test.dart
View file @
ef5abcc6
...
...
@@ -898,6 +898,51 @@ void main() {
semantics
.
dispose
();
});
testWidgets
(
'changing selection with keyboard does not show handles'
,
(
WidgetTester
tester
)
async
{
const
String
value1
=
'Hello World'
;
controller
.
text
=
value1
;
await
tester
.
pumpWidget
(
MaterialApp
(
home:
EditableText
(
backgroundCursorColor:
Colors
.
grey
,
controller:
controller
,
selectionControls:
materialTextSelectionControls
,
focusNode:
focusNode
,
style:
textStyle
,
cursorColor:
cursorColor
,
),
),
);
// Simulate selection change via tap to show handles.
final
RenderEditable
render
=
tester
.
allRenderObjects
.
firstWhere
((
RenderObject
o
)
=>
o
.
runtimeType
==
RenderEditable
);
render
.
onSelectionChanged
(
const
TextSelection
.
collapsed
(
offset:
4
),
render
,
SelectionChangedCause
.
tap
);
await
tester
.
pumpAndSettle
();
final
EditableTextState
textState
=
tester
.
state
(
find
.
byType
(
EditableText
));
expect
(
textState
.
selectionOverlay
.
handlesAreVisible
,
isTrue
);
expect
(
textState
.
selectionOverlay
.
selectionDelegate
.
textEditingValue
.
selection
,
const
TextSelection
.
collapsed
(
offset:
4
),
);
// Simulate selection change via keyboard and expect handles to disappear.
render
.
onSelectionChanged
(
const
TextSelection
.
collapsed
(
offset:
10
),
render
,
SelectionChangedCause
.
keyboard
);
await
tester
.
pumpAndSettle
();
expect
(
textState
.
selectionOverlay
.
handlesAreVisible
,
isFalse
);
expect
(
textState
.
selectionOverlay
.
selectionDelegate
.
textEditingValue
.
selection
,
const
TextSelection
.
collapsed
(
offset:
10
),
);
});
testWidgets
(
'exposes correct cursor movement semantics'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
...
...
@@ -1989,7 +2034,6 @@ void main() {
// Select the first word. Both handles should be visible.
await
tester
.
tapAt
(
const
Offset
(
20
,
10
));
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
state
.
showHandles
();
await
tester
.
pump
();
await
verifyVisibility
(
HandlePositionInViewport
.
leftEdge
,
true
,
HandlePositionInViewport
.
within
,
true
);
...
...
@@ -2011,7 +2055,6 @@ void main() {
// Now that the second word has been dragged fully into view, select it.
await
tester
.
tapAt
(
const
Offset
(
80
,
10
));
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
state
.
showHandles
();
await
tester
.
pump
();
await
verifyVisibility
(
HandlePositionInViewport
.
within
,
true
,
HandlePositionInViewport
.
within
,
true
);
...
...
@@ -2056,7 +2099,6 @@ void main() {
// Select the first word. Both handles should be visible.
await
tester
.
tapAt
(
const
Offset
(
20
,
10
));
state
.
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
state
.
showHandles
();
await
tester
.
pump
();
final
List
<
Positioned
>
positioned
=
find
.
byType
(
Positioned
).
evaluate
().
map
((
Element
e
)
=>
e
.
widget
).
cast
<
Positioned
>().
toList
();
...
...
@@ -2176,7 +2218,6 @@ void main() {
// Select the first word. Both handles should be visible.
await
tester
.
tapAt
(
const
Offset
(
20
,
10
));
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
state
.
showHandles
();
await
tester
.
pump
();
await
verifyVisibility
(
HandlePositionInViewport
.
leftEdge
,
true
,
HandlePositionInViewport
.
within
,
true
);
...
...
@@ -2198,7 +2239,6 @@ void main() {
// Now that the second word has been dragged fully into view, select it.
await
tester
.
tapAt
(
const
Offset
(
80
,
10
));
renderEditable
.
selectWord
(
cause:
SelectionChangedCause
.
longPress
);
state
.
showHandles
();
await
tester
.
pump
();
await
verifyVisibility
(
HandlePositionInViewport
.
within
,
true
,
HandlePositionInViewport
.
within
,
true
);
...
...
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