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
b0d4d448
Unverified
Commit
b0d4d448
authored
Mar 02, 2021
by
chunhtai
Committed by
GitHub
Mar 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reland "fixes TextInputFormatter gets wrong old value of a selection" (#76653)
parent
297c7b5c
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
324 additions
and
205 deletions
+324
-205
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+1
-0
selectable_text.dart
packages/flutter/lib/src/material/selectable_text.dart
+6
-2
editable.dart
packages/flutter/lib/src/rendering/editable.dart
+59
-92
text_input.dart
packages/flutter/lib/src/services/text_input.dart
+52
-4
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+55
-59
text_selection.dart
packages/flutter/lib/src/widgets/text_selection.dart
+41
-23
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+0
-2
text_field_focus_test.dart
packages/flutter/test/material/text_field_focus_test.dart
+2
-0
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+63
-6
editable_test.dart
packages/flutter/test/rendering/editable_test.dart
+3
-0
editable_text_cursor_test.dart
packages/flutter/test/widgets/editable_text_cursor_test.dart
+9
-6
editable_text_show_on_screen_test.dart
...utter/test/widgets/editable_text_show_on_screen_test.dart
+8
-2
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+24
-9
text_selection_test.dart
packages/flutter/test/widgets/text_selection_test.dart
+1
-0
No files found.
packages/flutter/lib/src/cupertino/text_field.dart
View file @
b0d4d448
...
...
@@ -102,6 +102,7 @@ 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/selectable_text.dart
View file @
b0d4d448
...
...
@@ -494,6 +494,8 @@ class _SelectableTextState extends State<SelectableText> with AutomaticKeepAlive
});
}
TextSelection
?
_lastSeenTextSelection
;
void
_handleSelectionChanged
(
TextSelection
selection
,
SelectionChangedCause
?
cause
)
{
final
bool
willShowSelectionHandles
=
_shouldShowSelectionHandles
(
cause
);
if
(
willShowSelectionHandles
!=
_showSelectionHandles
)
{
...
...
@@ -501,10 +503,12 @@ class _SelectableTextState extends State<SelectableText> with AutomaticKeepAlive
_showSelectionHandles
=
willShowSelectionHandles
;
});
}
if
(
widget
.
onSelectionChanged
!=
null
)
{
// TODO(chunhtai): The selection may be the same. We should remove this
// check once this is fixed https://github.com/flutter/flutter/issues/76349.
if
(
widget
.
onSelectionChanged
!=
null
&&
_lastSeenTextSelection
!=
selection
)
{
widget
.
onSelectionChanged
!(
selection
,
cause
);
}
_lastSeenTextSelection
=
selection
;
switch
(
Theme
.
of
(
context
).
platform
)
{
case
TargetPlatform
.
iOS
:
...
...
packages/flutter/lib/src/rendering/editable.dart
View file @
b0d4d448
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/services/text_input.dart
View file @
b0d4d448
...
...
@@ -754,12 +754,60 @@ class TextEditingValue {
);
}
/// Indicates what triggered the change in selected text (including changes to
/// the cursor location).
enum
SelectionChangedCause
{
/// The user tapped on the text and that caused the selection (or the location
/// of the cursor) to change.
tap
,
/// The user tapped twice in quick succession on the text and that caused
/// the selection (or the location of the cursor) to change.
doubleTap
,
/// The user long-pressed the text and that caused the selection (or the
/// location of the cursor) to change.
longPress
,
/// The user force-pressed the text and that caused the selection (or the
/// location of the cursor) to change.
forcePress
,
/// The user used the keyboard to change the selection or the location of the
/// cursor.
///
/// Keyboard-triggered selection changes may be caused by the IME as well as
/// by accessibility tools (e.g. TalkBack on Android).
keyboard
,
/// The user used the selection toolbar to change the selection or the
/// location of the cursor.
///
/// An example is when the user taps on select all in the tool bar.
toolBar
,
/// The user used the mouse to change the selection by dragging over a piece
/// of text.
drag
,
}
/// An interface for manipulating the selection, to be used by the implementor
/// of the toolbar widget.
abstract
class
TextSelectionDelegate
{
/// Gets the current text input.
TextEditingValue
get
textEditingValue
;
/// Indicates that the user has requested the delegate to replace its current
/// text editing state with [value].
///
/// The new [value] is treated as user input and thus may subject to input
/// formatting.
@Deprecated
(
'Use the userUpdateTextEditingValue instead. '
'This feature was deprecated after v1.26.0-17.2.pre.'
)
set
textEditingValue
(
TextEditingValue
value
)
{}
/// Indicates that the user has requested the delegate to replace its current
/// text editing state with [value].
///
...
...
@@ -768,10 +816,10 @@ abstract class TextSelectionDelegate {
///
/// See also:
///
/// * [EditableTextState.
textEditingValue]: an implementation that applies
/// a
dditional pre-processing to the specified [value], before updating th
e
/// text editing state.
set
textEditingValue
(
TextEditingValue
valu
e
);
/// * [EditableTextState.
userUpdateTextEditingValue]: an implementation that
/// a
pplies additional pre-processing to the specified [value], befor
e
///
updating the
text editing state.
void
userUpdateTextEditingValue
(
TextEditingValue
value
,
SelectionChangedCause
caus
e
);
/// Hides the text selection toolbar.
///
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
b0d4d448
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/text_selection.dart
View file @
b0d4d448
...
...
@@ -205,12 +205,15 @@ abstract class TextSelectionControls {
Clipboard
.
setData
(
ClipboardData
(
text:
value
.
selection
.
textInside
(
value
.
text
),
));
delegate
.
textEditingValue
=
TextEditingValue
(
text:
value
.
selection
.
textBefore
(
value
.
text
)
+
value
.
selection
.
textAfter
(
value
.
text
),
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
start
delegate
.
userUpdateTextEditingValue
(
TextEditingValue
(
text:
value
.
selection
.
textBefore
(
value
.
text
)
+
value
.
selection
.
textAfter
(
value
.
text
),
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
start
)
),
SelectionChangedCause
.
toolBar
,
);
delegate
.
bringIntoView
(
delegate
.
textEditingValue
.
selection
.
extent
);
delegate
.
hideToolbar
();
...
...
@@ -241,9 +244,12 @@ abstract class TextSelectionControls {
case
TargetPlatform
.
linux
:
case
TargetPlatform
.
windows
:
// Collapse the selection and hide the toolbar and handles.
delegate
.
textEditingValue
=
TextEditingValue
(
text:
value
.
text
,
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
end
),
delegate
.
userUpdateTextEditingValue
(
TextEditingValue
(
text:
value
.
text
,
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
end
),
),
SelectionChangedCause
.
toolBar
,
);
delegate
.
hideToolbar
();
return
;
...
...
@@ -265,13 +271,16 @@ abstract class TextSelectionControls {
final
TextEditingValue
value
=
delegate
.
textEditingValue
;
// Snapshot the input before using `await`.
final
ClipboardData
?
data
=
await
Clipboard
.
getData
(
Clipboard
.
kTextPlain
);
if
(
data
!=
null
)
{
delegate
.
textEditingValue
=
TextEditingValue
(
text:
value
.
selection
.
textBefore
(
value
.
text
)
+
data
.
text
!
+
value
.
selection
.
textAfter
(
value
.
text
),
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
start
+
data
.
text
!.
length
delegate
.
userUpdateTextEditingValue
(
TextEditingValue
(
text:
value
.
selection
.
textBefore
(
value
.
text
)
+
data
.
text
!
+
value
.
selection
.
textAfter
(
value
.
text
),
selection:
TextSelection
.
collapsed
(
offset:
value
.
selection
.
start
+
data
.
text
!.
length
),
),
SelectionChangedCause
.
toolBar
,
);
}
delegate
.
bringIntoView
(
delegate
.
textEditingValue
.
selection
.
extent
);
...
...
@@ -286,12 +295,15 @@ abstract class TextSelectionControls {
/// This is called by subclasses when their select-all affordance is activated
/// by the user.
void
handleSelectAll
(
TextSelectionDelegate
delegate
)
{
delegate
.
textEditingValue
=
TextEditingValue
(
text:
delegate
.
textEditingValue
.
text
,
selection:
TextSelection
(
baseOffset:
0
,
extentOffset:
delegate
.
textEditingValue
.
text
.
length
,
delegate
.
userUpdateTextEditingValue
(
TextEditingValue
(
text:
delegate
.
textEditingValue
.
text
,
selection:
TextSelection
(
baseOffset:
0
,
extentOffset:
delegate
.
textEditingValue
.
text
.
length
,
),
),
SelectionChangedCause
.
toolBar
,
);
delegate
.
bringIntoView
(
delegate
.
textEditingValue
.
selection
.
extent
);
}
...
...
@@ -450,13 +462,16 @@ class TextSelectionOverlay {
/// Builds the handles by inserting them into the [context]'s overlay.
void
showHandles
()
{
assert
(
_handles
==
null
);
if
(
_handles
!=
null
)
return
;
_handles
=
<
OverlayEntry
>[
OverlayEntry
(
builder:
(
BuildContext
context
)
=>
_buildHandle
(
context
,
_TextSelectionHandlePosition
.
start
)),
OverlayEntry
(
builder:
(
BuildContext
context
)
=>
_buildHandle
(
context
,
_TextSelectionHandlePosition
.
end
)),
];
Overlay
.
of
(
context
,
rootOverlay:
true
,
debugRequiredFor:
debugRequiredFor
)!.
insertAll
(
_handles
!);
Overlay
.
of
(
context
,
rootOverlay:
true
,
debugRequiredFor:
debugRequiredFor
)!
.
insertAll
(
_handles
!);
}
/// Destroys the handles by removing them from overlay.
...
...
@@ -636,10 +651,13 @@ class TextSelectionOverlay {
textPosition
=
newSelection
.
base
;
break
;
case
_TextSelectionHandlePosition
.
end
:
textPosition
=
newSelection
.
extent
;
textPosition
=
newSelection
.
extent
;
break
;
}
selectionDelegate
!.
textEditingValue
=
_value
.
copyWith
(
selection:
newSelection
,
composing:
TextRange
.
empty
);
selectionDelegate
!.
userUpdateTextEditingValue
(
_value
.
copyWith
(
selection:
newSelection
,
composing:
TextRange
.
empty
),
SelectionChangedCause
.
drag
,
);
selectionDelegate
!.
bringIntoView
(
textPosition
);
}
}
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
b0d4d448
...
...
@@ -3475,7 +3475,6 @@ void main() {
from:
tester
.
getTopRight
(
find
.
byType
(
CupertinoApp
)),
cause:
SelectionChangedCause
.
tap
,
);
expect
(
state
.
showToolbar
(),
true
);
await
tester
.
pumpAndSettle
();
// -1 because we want to reach the end of the line, not the start of a new line.
...
...
@@ -3536,7 +3535,6 @@ void main() {
from:
tester
.
getCenter
(
find
.
byType
(
EditableText
)),
cause:
SelectionChangedCause
.
tap
,
);
expect
(
state
.
showToolbar
(),
true
);
await
tester
.
pumpAndSettle
();
bottomLeftSelectionPosition
=
textOffsetToBottomLeftPosition
(
tester
,
state
.
renderEditable
.
selection
!.
baseOffset
);
...
...
packages/flutter/test/material/text_field_focus_test.dart
View file @
b0d4d448
...
...
@@ -119,6 +119,8 @@ void main() {
expect
(
tester
.
testTextInput
.
isVisible
,
isTrue
);
tester
.
testTextInput
.
hide
();
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
state
.
connectionClosed
();
expect
(
tester
.
testTextInput
.
isVisible
,
isFalse
);
...
...
packages/flutter/test/material/text_field_test.dart
View file @
b0d4d448
...
...
@@ -18,6 +18,8 @@ import '../widgets/editable_text_utils.dart' show findRenderEditable, globalize,
import
'../widgets/semantics_tester.dart'
;
import
'feedback_tester.dart'
;
typedef
FormatEditUpdateCallback
=
void
Function
(
TextEditingValue
,
TextEditingValue
);
class
MockClipboard
{
Object
_clipboardData
=
<
String
,
dynamic
>{
'text'
:
null
,
...
...
@@ -127,6 +129,16 @@ double getOpacity(WidgetTester tester, Finder finder) {
).
opacity
.
value
;
}
class
TestFormatter
extends
TextInputFormatter
{
TestFormatter
(
this
.
onFormatEditUpdate
);
FormatEditUpdateCallback
onFormatEditUpdate
;
@override
TextEditingValue
formatEditUpdate
(
TextEditingValue
oldValue
,
TextEditingValue
newValue
)
{
onFormatEditUpdate
(
oldValue
,
newValue
);
return
newValue
;
}
}
void
main
(
)
{
TestWidgetsFlutterBinding
.
ensureInitialized
();
final
MockClipboard
mockClipboard
=
MockClipboard
();
...
...
@@ -474,6 +486,47 @@ void main() {
);
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
testWidgets
(
'TextInputFormatter gets correct selection value'
,
(
WidgetTester
tester
)
async
{
late
TextEditingValue
actualOldValue
;
late
TextEditingValue
actualNewValue
;
final
FormatEditUpdateCallback
callBack
=
(
TextEditingValue
oldValue
,
TextEditingValue
newValue
)
{
actualOldValue
=
oldValue
;
actualNewValue
=
newValue
;
};
final
FocusNode
focusNode
=
FocusNode
();
final
TextEditingController
controller
=
TextEditingController
(
text:
'123'
);
await
tester
.
pumpWidget
(
boilerplate
(
child:
TextField
(
controller:
controller
,
focusNode:
focusNode
,
inputFormatters:
<
TextInputFormatter
>[
TestFormatter
(
callBack
)],
),
),
);
await
tester
.
tap
(
find
.
byType
(
TextField
));
await
tester
.
pumpAndSettle
();
await
tester
.
sendKeyEvent
(
LogicalKeyboardKey
.
backspace
);
await
tester
.
pumpAndSettle
();
expect
(
actualOldValue
,
const
TextEditingValue
(
text:
'123'
,
selection:
TextSelection
.
collapsed
(
offset:
3
,
affinity:
TextAffinity
.
upstream
),
),
);
expect
(
actualNewValue
,
const
TextEditingValue
(
text:
'12'
,
selection:
TextSelection
.
collapsed
(
offset:
2
),
),
);
});
testWidgets
(
'text field selection toolbar renders correctly inside opacity'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -1071,11 +1124,9 @@ void main() {
));
expect
(
find
.
text
(
'Paste'
),
findsNothing
);
final
Offset
emptyPos
=
textOffsetToPosition
(
tester
,
0
);
await
tester
.
longPressAt
(
emptyPos
,
pointer:
7
);
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'Paste'
),
findsOneWidget
);
});
...
...
@@ -3497,8 +3548,11 @@ void main() {
// scrolls to make the caret visible.
scrollableState
=
tester
.
firstState
(
find
.
byType
(
Scrollable
));
final
EditableTextState
editableTextState
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
editableTextState
.
textEditingValue
=
editableTextState
.
textEditingValue
.
copyWith
(
selection:
TextSelection
.
collapsed
(
offset:
longText
.
length
),
editableTextState
.
userUpdateTextEditingValue
(
editableTextState
.
textEditingValue
.
copyWith
(
selection:
TextSelection
.
collapsed
(
offset:
longText
.
length
),
),
null
,
);
await
tester
.
pump
();
// TODO(ianh): Figure out why this extra pump is needed.
...
...
@@ -3533,8 +3587,11 @@ void main() {
// Move the caret to the end of the text and check that the text field
// scrolls to make the caret visible.
final
EditableTextState
editableTextState
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
editableTextState
.
textEditingValue
=
editableTextState
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
tallText
.
length
),
editableTextState
.
userUpdateTextEditingValue
(
editableTextState
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
tallText
.
length
),
),
null
,
);
await
tester
.
pump
();
await
skipPastScrollingAnimation
(
tester
);
...
...
packages/flutter/test/rendering/editable_test.dart
View file @
b0d4d448
...
...
@@ -21,6 +21,9 @@ class FakeEditableTextState with TextSelectionDelegate {
@override
void
hideToolbar
([
bool
hideHandles
=
true
])
{
}
@override
void
userUpdateTextEditingValue
(
TextEditingValue
value
,
SelectionChangedCause
cause
)
{
}
@override
void
bringIntoView
(
TextPosition
position
)
{
}
}
...
...
packages/flutter/test/widgets/editable_text_cursor_test.dart
View file @
b0d4d448
...
...
@@ -48,6 +48,7 @@ void main() {
});
testWidgets
(
'cursor layout has correct width'
,
(
WidgetTester
tester
)
async
{
EditableText
.
debugDeterministicCursor
=
true
;
final
GlobalKey
<
EditableTextState
>
editableTextKey
=
GlobalKey
<
EditableTextState
>();
late
String
changedValue
;
...
...
@@ -87,8 +88,7 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
tap
(
find
.
text
(
'Paste'
));
// Wait for cursor to appear.
await
tester
.
pump
(
const
Duration
(
milliseconds:
600
));
await
tester
.
pump
();
expect
(
changedValue
,
clipboardContent
);
...
...
@@ -96,6 +96,7 @@ void main() {
find
.
byKey
(
const
ValueKey
<
int
>(
1
)),
matchesGoldenFile
(
'editable_text_test.0.png'
),
);
EditableText
.
debugDeterministicCursor
=
false
;
});
testWidgets
(
'cursor layout has correct radius'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -787,6 +788,7 @@ void main() {
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
testWidgets
(
'cursor layout'
,
(
WidgetTester
tester
)
async
{
EditableText
.
debugDeterministicCursor
=
true
;
final
GlobalKey
<
EditableTextState
>
editableTextKey
=
GlobalKey
<
EditableTextState
>();
late
String
changedValue
;
...
...
@@ -831,8 +833,7 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
tap
(
find
.
text
(
'Paste'
));
// Wait for cursor to appear.
await
tester
.
pump
(
const
Duration
(
milliseconds:
600
));
await
tester
.
pump
();
expect
(
changedValue
,
clipboardContent
);
...
...
@@ -840,9 +841,11 @@ void main() {
find
.
byKey
(
const
ValueKey
<
int
>(
1
)),
matchesGoldenFile
(
'editable_text_test.2.png'
),
);
EditableText
.
debugDeterministicCursor
=
false
;
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
testWidgets
(
'cursor layout has correct height'
,
(
WidgetTester
tester
)
async
{
EditableText
.
debugDeterministicCursor
=
true
;
final
GlobalKey
<
EditableTextState
>
editableTextKey
=
GlobalKey
<
EditableTextState
>();
late
String
changedValue
;
...
...
@@ -888,8 +891,7 @@ void main() {
await
tester
.
pumpAndSettle
();
await
tester
.
tap
(
find
.
text
(
'Paste'
));
// Wait for cursor to appear.
await
tester
.
pump
(
const
Duration
(
milliseconds:
600
));
await
tester
.
pump
();
expect
(
changedValue
,
clipboardContent
);
...
...
@@ -897,5 +899,6 @@ void main() {
find
.
byKey
(
const
ValueKey
<
int
>(
1
)),
matchesGoldenFile
(
'editable_text_test.3.png'
),
);
EditableText
.
debugDeterministicCursor
=
false
;
},
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
,
TargetPlatform
.
macOS
}));
}
packages/flutter/test/widgets/editable_text_show_on_screen_test.dart
View file @
b0d4d448
...
...
@@ -646,7 +646,10 @@ void main() {
// Change the selection. Show caret on screen even when readyOnly is
// false.
state
.
textEditingValue
=
state
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
90
));
state
.
userUpdateTextEditingValue
(
state
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
90
)),
null
,
);
await
tester
.
pumpAndSettle
();
expect
(
isCaretOnScreen
(
tester
),
isTrue
);
expect
(
scrollController
.
offset
,
greaterThan
(
0.0
));
...
...
@@ -667,7 +670,10 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
isCaretOnScreen
(
tester
),
isFalse
);
state
.
textEditingValue
=
state
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
100
));
state
.
userUpdateTextEditingValue
(
state
.
textEditingValue
.
copyWith
(
selection:
const
TextSelection
.
collapsed
(
offset:
100
)),
null
,
);
await
tester
.
pumpAndSettle
();
expect
(
isCaretOnScreen
(
tester
),
isTrue
);
expect
(
scrollController
.
offset
,
greaterThan
(
0.0
));
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
b0d4d448
...
...
@@ -5198,7 +5198,7 @@ void main() {
tester
.
testTextInput
.
log
.
clear
();
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byWidget
(
editableText
));
state
.
textEditingValue
=
const
TextEditingValue
(
text:
'remoteremoteremote'
);
state
.
userUpdateTextEditingValue
(
const
TextEditingValue
(
text:
'remoteremoteremote'
),
SelectionChangedCause
.
keyboard
);
// Apply in order: length formatter -> listener -> onChanged -> listener.
expect
(
controller
.
text
,
'remote listener onChanged listener'
);
...
...
@@ -5354,6 +5354,7 @@ void main() {
'TextInput.setEditingState'
,
'TextInput.setEditingState'
,
'TextInput.show'
,
'TextInput.show'
,
];
expect
(
tester
.
testTextInput
.
log
.
length
,
logOrder
.
length
);
int
index
=
0
;
...
...
@@ -5468,16 +5469,18 @@ void main() {
log
.
clear
();
final
EditableTextState
state
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
// setEditingState is not called when only the remote changes
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'a'
,
selection:
controller
.
selection
,
));
expect
(
log
.
length
,
0
);
// setEditingState is called when remote value modified by the formatter.
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'I will be modified by the formatter.'
,
selection:
controller
.
selection
,
));
expect
(
log
.
length
,
1
);
MethodCall
methodCall
=
log
[
0
];
...
...
@@ -5591,8 +5594,9 @@ void main() {
final
EditableTextState
state
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
// setEditingState is called when remote value modified by the formatter.
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'I will be modified by the formatter.'
,
selection:
controller
.
selection
,
));
expect
(
log
.
length
,
1
);
expect
(
log
,
contains
(
matchesMethodCall
(
...
...
@@ -5664,8 +5668,9 @@ void main() {
final
EditableTextState
state
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'a'
,
selection:
controller
.
selection
,
));
await
tester
.
pump
();
...
...
@@ -5688,8 +5693,9 @@ void main() {
log
.
clear
();
// Send repeat value from the engine.
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'a'
,
selection:
controller
.
selection
,
));
await
tester
.
pump
();
...
...
@@ -5783,8 +5789,9 @@ void main() {
final
EditableTextState
state
=
tester
.
firstState
(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
state
.
updateEditingValue
(
TextEditingValue
(
text:
'a'
,
selection:
controller
.
selection
,
));
await
tester
.
pump
();
...
...
@@ -6578,6 +6585,7 @@ void main() {
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
controller
.
selection
=
const
TextSelection
.
collapsed
(
offset:
2
);
...
...
@@ -6586,6 +6594,7 @@ void main() {
// Reset the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
expect
(
state
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
4
,
end:
12
));
...
...
@@ -6593,13 +6602,14 @@ void main() {
// Positioning cursor after the composing range should clear the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
controller
.
selection
=
const
TextSelection
.
collapsed
(
offset:
14
);
expect
(
state
.
currentTextEditingValue
.
composing
,
TextRange
.
empty
);
});
testWidgets
(
'Clears composing range if cursor moves outside that range'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Clears composing range if cursor moves outside that range
- case two
'
,
(
WidgetTester
tester
)
async
{
final
Widget
widget
=
MaterialApp
(
home:
EditableText
(
backgroundCursorColor:
Colors
.
grey
,
...
...
@@ -6616,6 +6626,7 @@ void main() {
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
controller
.
selection
=
const
TextSelection
(
baseOffset:
1
,
extentOffset:
2
);
...
...
@@ -6624,6 +6635,7 @@ void main() {
// Reset the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
expect
(
state
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
4
,
end:
12
));
...
...
@@ -6631,6 +6643,7 @@ void main() {
// Setting a selection within the composing range clears the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
controller
.
selection
=
const
TextSelection
(
baseOffset:
5
,
extentOffset:
7
);
...
...
@@ -6639,6 +6652,7 @@ void main() {
// Reset the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
expect
(
state
.
currentTextEditingValue
.
composing
,
const
TextRange
(
start:
4
,
end:
12
));
...
...
@@ -6646,6 +6660,7 @@ void main() {
// Setting a selection after the composing range clears the composing range.
state
.
updateEditingValue
(
const
TextEditingValue
(
text:
'foo composing bar'
,
selection:
TextSelection
.
collapsed
(
offset:
4
),
composing:
TextRange
(
start:
4
,
end:
12
),
));
controller
.
selection
=
const
TextSelection
(
baseOffset:
13
,
extentOffset:
15
);
...
...
packages/flutter/test/widgets/text_selection_test.dart
View file @
b0d4d448
...
...
@@ -797,6 +797,7 @@ class FakeRenderEditable extends RenderEditable {
),
startHandleLayerLink:
LayerLink
(),
endHandleLayerLink:
LayerLink
(),
ignorePointer:
true
,
textAlign:
TextAlign
.
start
,
textDirection:
TextDirection
.
ltr
,
locale:
const
Locale
(
'en'
,
'US'
),
...
...
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