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
bcc1dc6b
Unverified
Commit
bcc1dc6b
authored
Sep 16, 2022
by
chunhtai
Committed by
GitHub
Sep 16, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Makes TextBoundary and its subclasses public (#110367)
parent
a7f028f1
Changes
11
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
518 additions
and
290 deletions
+518
-290
services.dart
packages/flutter/lib/services.dart
+1
-0
text_painter.dart
packages/flutter/lib/src/painting/text_painter.dart
+6
-0
editable.dart
packages/flutter/lib/src/rendering/editable.dart
+19
-6
text_boundary.dart
packages/flutter/lib/src/services/text_boundary.dart
+179
-0
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+173
-267
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+4
-2
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+8
-13
text_boundary_test.dart
packages/flutter/test/services/text_boundary_test.dart
+97
-0
editable_text_shortcuts_test.dart
...es/flutter/test/widgets/editable_text_shortcuts_test.dart
+7
-0
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+22
-1
editable_text_utils.dart
packages/flutter/test/widgets/editable_text_utils.dart
+2
-1
No files found.
packages/flutter/lib/services.dart
View file @
bcc1dc6b
...
...
@@ -43,6 +43,7 @@ export 'src/services/system_channels.dart';
export
'src/services/system_chrome.dart'
;
export
'src/services/system_navigator.dart'
;
export
'src/services/system_sound.dart'
;
export
'src/services/text_boundary.dart'
;
export
'src/services/text_editing.dart'
;
export
'src/services/text_editing_delta.dart'
;
export
'src/services/text_formatter.dart'
;
...
...
packages/flutter/lib/src/painting/text_painter.dart
View file @
bcc1dc6b
...
...
@@ -1129,6 +1129,12 @@ class TextPainter {
/// {@endtemplate}
TextRange
getWordBoundary
(
TextPosition
position
)
{
assert
(
_debugAssertTextLayoutIsValid
);
// TODO(chunhtai): remove this workaround once ui.Paragraph.getWordBoundary
// can handle caret position.
// https://github.com/flutter/flutter/issues/111751.
if
(
position
.
affinity
==
TextAffinity
.
upstream
)
{
position
=
TextPosition
(
offset:
position
.
offset
-
1
);
}
return
_paragraph
!.
getWordBoundary
(
position
);
}
...
...
packages/flutter/lib/src/rendering/editable.dart
View file @
bcc1dc6b
...
...
@@ -2040,7 +2040,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
final
TextSelection
firstWord
=
_getWordAtOffset
(
firstPosition
);
final
TextSelection
lastWord
=
to
==
null
?
firstWord
:
_getWordAtOffset
(
_textPainter
.
getPositionForOffset
(
globalToLocal
(
to
-
_paintOffset
)));
_setSelection
(
TextSelection
(
baseOffset:
firstWord
.
base
.
offset
,
...
...
@@ -2071,14 +2070,28 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
TextSelection
_getWordAtOffset
(
TextPosition
position
)
{
debugAssertLayoutUpToDate
();
final
TextRange
word
=
_textPainter
.
getWordBoundary
(
position
);
// When long-pressing past the end of the text, we want a collapsed cursor.
if
(
position
.
offset
>=
word
.
end
)
{
return
TextSelection
.
fromPosition
(
position
);
if
(
position
.
offset
>=
_plainText
.
length
)
{
return
TextSelection
.
fromPosition
(
TextPosition
(
offset:
_plainText
.
length
,
affinity:
TextAffinity
.
upstream
)
);
}
// If text is obscured, the entire sentence should be treated as one word.
if
(
obscureText
)
{
return
TextSelection
(
baseOffset:
0
,
extentOffset:
_plainText
.
length
);
}
final
TextRange
word
=
_textPainter
.
getWordBoundary
(
position
);
final
int
effectiveOffset
;
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
// upstream affinity is effectively -1 in text position.
effectiveOffset
=
position
.
offset
-
1
;
break
;
case
TextAffinity
.
downstream
:
effectiveOffset
=
position
.
offset
;
break
;
}
// On iOS, select the previous word if there is a previous word, or select
// to the end of the next word if there is a next word. Select nothing if
// there is neither a previous word nor a next word.
...
...
@@ -2086,8 +2099,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
// If the platform is Android and the text is read only, try to select the
// previous word if there is one; otherwise, select the single whitespace at
// the position.
}
else
if
(
TextLayoutMetrics
.
isWhitespace
(
_plainText
.
codeUnitAt
(
position
.
o
ffset
))
&&
position
.
o
ffset
>
0
)
{
if
(
TextLayoutMetrics
.
isWhitespace
(
_plainText
.
codeUnitAt
(
effectiveO
ffset
))
&&
effectiveO
ffset
>
0
)
{
assert
(
defaultTargetPlatform
!=
null
);
final
TextRange
?
previousWord
=
_getPreviousWord
(
word
.
start
);
switch
(
defaultTargetPlatform
)
{
...
...
packages/flutter/lib/src/services/text_boundary.dart
0 → 100644
View file @
bcc1dc6b
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:math'
as
math
;
import
'dart:ui'
;
import
'package:characters/characters.dart'
show
CharacterRange
;
import
'text_layout_metrics.dart'
;
/// An interface for retrieving the logical text boundary (left-closed-right-open)
/// at a given location in a document.
///
/// The input [TextPosition] points to a position between 2 code units (which
/// can be visually represented by the caret if the selection were to collapse
/// to that position). The [TextPosition.affinity] is used to determine which
/// code unit it points. For example, `TextPosition(i, upstream)` points to
/// code unit `i - 1` and `TextPosition(i, downstream)` points to code unit `i`.
abstract
class
TextBoundary
{
/// A constant constructor to enable subclass override.
const
TextBoundary
();
/// Returns the leading text boundary at the given location.
///
/// The return value must be less or equal to the input position.
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
);
/// Returns the trailing text boundary at the given location, exclusive.
///
/// The return value must be greater or equal to the input position.
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
);
/// Gets the text boundary range that encloses the input position.
TextRange
getTextBoundaryAt
(
TextPosition
position
)
{
return
TextRange
(
start:
getLeadingTextBoundaryAt
(
position
).
offset
,
end:
getTrailingTextBoundaryAt
(
position
).
offset
,
);
}
}
/// A text boundary that uses characters as logical boundaries.
///
/// This class takes grapheme clusters into account and avoid creating
/// boundaries that generate malformed utf-16 characters.
class
CharacterBoundary
extends
TextBoundary
{
/// Creates a [CharacterBoundary] with the text.
const
CharacterBoundary
(
this
.
_text
);
final
String
_text
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
if
(
position
.
offset
<=
0
)
{
return
const
TextPosition
(
offset:
0
);
}
if
(
position
.
offset
>
_text
.
length
||
(
position
.
offset
==
_text
.
length
&&
position
.
affinity
==
TextAffinity
.
downstream
))
{
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
final
int
endOffset
;
final
int
startOffset
;
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
startOffset
=
math
.
min
(
position
.
offset
-
1
,
_text
.
length
);
endOffset
=
math
.
min
(
position
.
offset
,
_text
.
length
);
break
;
case
TextAffinity
.
downstream
:
startOffset
=
math
.
min
(
position
.
offset
,
_text
.
length
);
endOffset
=
math
.
min
(
position
.
offset
+
1
,
_text
.
length
);
break
;
}
return
TextPosition
(
offset:
CharacterRange
.
at
(
_text
,
startOffset
,
endOffset
).
stringBeforeLength
,
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
if
(
position
.
offset
<
0
||
(
position
.
offset
==
0
&&
position
.
affinity
==
TextAffinity
.
upstream
))
{
return
const
TextPosition
(
offset:
0
);
}
if
(
position
.
offset
>=
_text
.
length
)
{
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
);
}
final
int
endOffset
;
final
int
startOffset
;
switch
(
position
.
affinity
)
{
case
TextAffinity
.
upstream
:
startOffset
=
math
.
min
(
position
.
offset
-
1
,
_text
.
length
);
endOffset
=
math
.
min
(
position
.
offset
,
_text
.
length
);
break
;
case
TextAffinity
.
downstream
:
startOffset
=
math
.
min
(
position
.
offset
,
_text
.
length
);
endOffset
=
math
.
min
(
position
.
offset
+
1
,
_text
.
length
);
break
;
}
final
CharacterRange
range
=
CharacterRange
.
at
(
_text
,
startOffset
,
endOffset
);
return
TextPosition
(
offset:
_text
.
length
-
range
.
stringAfterLength
,
affinity:
TextAffinity
.
upstream
,
);
}
}
/// A text boundary that uses words as logical boundaries.
///
/// This class uses [UAX #29](https://unicode.org/reports/tr29/) defined word
/// boundaries to calculate its logical boundaries.
class
WordBoundary
extends
TextBoundary
{
/// Creates a [CharacterBoundary] with the text and layout information.
const
WordBoundary
(
this
.
_textLayout
);
final
TextLayoutMetrics
_textLayout
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
offset:
_textLayout
.
getWordBoundary
(
position
).
start
,
affinity:
TextAffinity
.
downstream
,
// ignore: avoid_redundant_argument_values
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
offset:
_textLayout
.
getWordBoundary
(
position
).
end
,
affinity:
TextAffinity
.
upstream
,
);
}
}
/// A text boundary that uses line breaks as logical boundaries.
///
/// The input [TextPosition]s will be interpreted as caret locations if
/// [TextLayoutMetrics.getLineAtOffset] is text-affinity-aware.
class
LineBreak
extends
TextBoundary
{
/// Creates a [CharacterBoundary] with the text and layout information.
const
LineBreak
(
this
.
_textLayout
);
final
TextLayoutMetrics
_textLayout
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
offset:
_textLayout
.
getLineAtOffset
(
position
).
start
,
);
}
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
offset:
_textLayout
.
getLineAtOffset
(
position
).
end
,
affinity:
TextAffinity
.
upstream
,
);
}
}
/// A text boundary that uses the entire document as logical boundary.
///
/// The document boundary is unique and is a constant function of the input
/// position.
class
DocumentBoundary
extends
TextBoundary
{
/// Creates a [CharacterBoundary] with the text
const
DocumentBoundary
(
this
.
_text
);
final
String
_text
;
@override
TextPosition
getLeadingTextBoundaryAt
(
TextPosition
position
)
=>
const
TextPosition
(
offset:
0
);
@override
TextPosition
getTrailingTextBoundaryAt
(
TextPosition
position
)
{
return
TextPosition
(
offset:
_text
.
length
,
affinity:
TextAffinity
.
upstream
,
);
}
}
packages/flutter/lib/src/widgets/editable_text.dart
View file @
bcc1dc6b
This diff is collapsed.
Click to expand it.
packages/flutter/test/cupertino/text_field_test.dart
View file @
bcc1dc6b
...
...
@@ -199,7 +199,8 @@ void main() {
return
endpoints
[
0
].
point
;
}
Offset
textOffsetToPosition
(
WidgetTester
tester
,
int
offset
)
=>
textOffsetToBottomLeftPosition
(
tester
,
offset
)
+
const
Offset
(
0
,
-
2
);
// Web has a less threshold for downstream/upstream text position.
Offset
textOffsetToPosition
(
WidgetTester
tester
,
int
offset
)
=>
textOffsetToBottomLeftPosition
(
tester
,
offset
)
+
const
Offset
(
kIsWeb
?
1
:
0
,
-
2
);
setUp
(()
async
{
EditableText
.
debugDeterministicCursor
=
false
;
...
...
@@ -2087,6 +2088,7 @@ void main() {
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
await
tester
.
tapAt
(
textOffsetToPosition
(
tester
,
5
));
await
tester
.
pumpAndSettle
();
expect
(
controller
.
value
.
selection
,
isNotNull
);
expect
(
controller
.
value
.
selection
.
baseOffset
,
5
);
expect
(
controller
.
value
.
selection
.
extentOffset
,
6
);
...
...
@@ -3053,7 +3055,7 @@ void main() {
expect
(
controller
.
selection
.
extentOffset
,
8
);
// Tiny movement shouldn't cause text selection to change.
await
gesture
.
moveTo
(
gPos
+
const
Offset
(
4
.0
,
0.0
));
await
gesture
.
moveTo
(
gPos
+
const
Offset
(
2
.0
,
0.0
));
await
tester
.
pumpAndSettle
();
expect
(
selectionChangedCount
,
0
);
...
...
packages/flutter/test/material/text_field_test.dart
View file @
bcc1dc6b
...
...
@@ -2172,7 +2172,7 @@ void main() {
expect
(
controller
.
selection
.
extentOffset
,
8
);
// Tiny movement shouldn't cause text selection to change.
await
gesture
.
moveTo
(
gPos
+
const
Offset
(
4
.0
,
0.0
));
await
gesture
.
moveTo
(
gPos
+
const
Offset
(
2
.0
,
0.0
));
await
tester
.
pumpAndSettle
();
expect
(
selectionChangedCount
,
0
);
...
...
@@ -3372,10 +3372,7 @@ void main() {
final
Offset
secondPos
=
textOffsetToPosition
(
tester
,
testValue
.
indexOf
(
'Second'
));
final
Offset
thirdPos
=
textOffsetToPosition
(
tester
,
testValue
.
indexOf
(
'Third'
));
final
Offset
middleStringPos
=
textOffsetToPosition
(
tester
,
testValue
.
indexOf
(
'irst'
));
expect
(
firstPos
.
dx
,
0
);
expect
(
secondPos
.
dx
,
0
);
expect
(
thirdPos
.
dx
,
0
);
expect
(
middleStringPos
.
dx
,
34
);
expect
(
firstPos
.
dx
,
lessThan
(
middleStringPos
.
dx
));
expect
(
firstPos
.
dx
,
secondPos
.
dx
);
expect
(
firstPos
.
dx
,
thirdPos
.
dx
);
expect
(
firstPos
.
dy
,
lessThan
(
secondPos
.
dy
));
...
...
@@ -3457,8 +3454,6 @@ void main() {
// Check that the last line of text is not displayed.
final
Offset
firstPos
=
textOffsetToPosition
(
tester
,
kMoreThanFourLines
.
indexOf
(
'First'
));
final
Offset
fourthPos
=
textOffsetToPosition
(
tester
,
kMoreThanFourLines
.
indexOf
(
'Fourth'
));
expect
(
firstPos
.
dx
,
0
);
expect
(
fourthPos
.
dx
,
0
);
expect
(
firstPos
.
dx
,
fourthPos
.
dx
);
expect
(
firstPos
.
dy
,
lessThan
(
fourthPos
.
dy
));
expect
(
inputBox
.
hitTest
(
BoxHitTestResult
(),
position:
inputBox
.
globalToLocal
(
firstPos
)),
isTrue
);
...
...
@@ -8397,10 +8392,10 @@ void main() {
),
),
);
final
Size
screenSize
=
MediaQuery
.
of
(
tester
.
element
(
find
.
byType
(
TextField
))).
size
;
// Just testing the test and making sure that the last character is off
// the right side of the screen.
expect
(
textOffsetToPosition
(
tester
,
66
).
dx
,
1056
);
expect
(
textOffsetToPosition
(
tester
,
66
).
dx
,
greaterThan
(
screenSize
.
width
)
);
final
TestGesture
gesture
=
await
tester
.
startGesture
(
...
...
@@ -8448,7 +8443,7 @@ void main() {
);
// The first character is now offscreen to the left.
expect
(
textOffsetToPosition
(
tester
,
0
).
dx
,
moreOrLessEquals
(-
257.0
,
epsilon:
1
));
expect
(
textOffsetToPosition
(
tester
,
0
).
dx
,
lessThan
(-
100.0
));
},
variant:
TargetPlatformVariant
.
all
());
testWidgets
(
'keyboard selection change scrolls the field'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -8485,7 +8480,7 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
56
),
const
TextSelection
.
collapsed
(
offset:
56
,
affinity:
TextAffinity
.
upstream
),
);
// Keep moving out.
...
...
@@ -8495,7 +8490,7 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
62
),
const
TextSelection
.
collapsed
(
offset:
62
,
affinity:
TextAffinity
.
upstream
),
);
for
(
int
i
=
0
;
i
<
(
66
-
62
);
i
+=
1
)
{
await
tester
.
sendKeyEvent
(
LogicalKeyboardKey
.
arrowRight
);
...
...
@@ -8503,7 +8498,7 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
66
),
const
TextSelection
.
collapsed
(
offset:
66
,
affinity:
TextAffinity
.
upstream
),
);
// We're at the edge now.
await
tester
.
pumpAndSettle
();
...
...
packages/flutter/test/services/text_boundary_test.dart
0 → 100644
View file @
bcc1dc6b
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
test
(
'Character boundary works'
,
()
{
const
CharacterBoundary
boundary
=
CharacterBoundary
(
'abc'
);
const
TextPosition
midPosition
=
TextPosition
(
offset:
1
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
midPosition
),
const
TextPosition
(
offset:
1
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
midPosition
),
const
TextPosition
(
offset:
2
,
affinity:
TextAffinity
.
upstream
));
const
TextPosition
startPosition
=
TextPosition
(
offset:
0
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
startPosition
),
const
TextPosition
(
offset:
0
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
startPosition
),
const
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
upstream
));
const
TextPosition
endPosition
=
TextPosition
(
offset:
3
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
endPosition
),
const
TextPosition
(
offset:
3
,
affinity:
TextAffinity
.
upstream
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
endPosition
),
const
TextPosition
(
offset:
3
,
affinity:
TextAffinity
.
upstream
));
});
test
(
'Character boundary works with grapheme'
,
()
{
const
String
text
=
'a❄︎c'
;
const
CharacterBoundary
boundary
=
CharacterBoundary
(
text
);
TextPosition
position
=
const
TextPosition
(
offset:
1
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
1
));
// The `❄` takes two character length.
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
3
,
affinity:
TextAffinity
.
upstream
));
position
=
const
TextPosition
(
offset:
2
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
1
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
3
,
affinity:
TextAffinity
.
upstream
));
position
=
const
TextPosition
(
offset:
0
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
0
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
1
,
affinity:
TextAffinity
.
upstream
));
position
=
const
TextPosition
(
offset:
text
.
length
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
text
.
length
,
affinity:
TextAffinity
.
upstream
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
text
.
length
,
affinity:
TextAffinity
.
upstream
));
});
test
(
'word boundary works'
,
()
{
final
WordBoundary
boundary
=
WordBoundary
(
TestTextLayoutMetrics
());
const
TextPosition
position
=
TextPosition
(
offset:
3
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
).
offset
,
TestTextLayoutMetrics
.
wordBoundaryAt3
.
start
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
).
offset
,
TestTextLayoutMetrics
.
wordBoundaryAt3
.
end
);
});
test
(
'line boundary works'
,
()
{
final
LineBreak
boundary
=
LineBreak
(
TestTextLayoutMetrics
());
const
TextPosition
position
=
TextPosition
(
offset:
3
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
).
offset
,
TestTextLayoutMetrics
.
lineAt3
.
start
);
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
).
offset
,
TestTextLayoutMetrics
.
lineAt3
.
end
);
});
test
(
'document boundary works'
,
()
{
const
String
text
=
'abcd efg hi
\n
jklmno
\n
pqrstuv'
;
const
DocumentBoundary
boundary
=
DocumentBoundary
(
text
);
const
TextPosition
position
=
TextPosition
(
offset:
10
);
expect
(
boundary
.
getLeadingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
0
));
expect
(
boundary
.
getTrailingTextBoundaryAt
(
position
),
const
TextPosition
(
offset:
text
.
length
,
affinity:
TextAffinity
.
upstream
));
});
}
class
TestTextLayoutMetrics
extends
TextLayoutMetrics
{
static
const
TextSelection
lineAt3
=
TextSelection
(
baseOffset:
0
,
extentOffset:
10
);
static
const
TextRange
wordBoundaryAt3
=
TextRange
(
start:
4
,
end:
7
);
@override
TextSelection
getLineAtOffset
(
TextPosition
position
)
{
if
(
position
.
offset
==
3
)
{
return
lineAt3
;
}
throw
UnimplementedError
();
}
@override
TextPosition
getTextPositionAbove
(
TextPosition
position
)
{
throw
UnimplementedError
();
}
@override
TextPosition
getTextPositionBelow
(
TextPosition
position
)
{
throw
UnimplementedError
();
}
@override
TextRange
getWordBoundary
(
TextPosition
position
)
{
if
(
position
.
offset
==
3
)
{
return
wordBoundaryAt3
;
}
throw
UnimplementedError
();
}
}
packages/flutter/test/widgets/editable_text_shortcuts_test.dart
View file @
bcc1dc6b
...
...
@@ -1229,6 +1229,7 @@ void main() {
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
21
,
affinity:
TextAffinity
.
upstream
,
));
},
variant:
TargetPlatformVariant
.
all
());
...
...
@@ -1243,6 +1244,7 @@ void main() {
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
10
,
affinity:
TextAffinity
.
upstream
,
));
},
variant:
allExceptApple
);
...
...
@@ -1353,6 +1355,7 @@ void main() {
await
tester
.
pump
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
46
,
// After "to".
affinity:
TextAffinity
.
upstream
,
));
// "good" to "come" is selected.
...
...
@@ -1365,6 +1368,7 @@ void main() {
await
tester
.
pump
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
28
,
// After "good".
affinity:
TextAffinity
.
upstream
,
));
},
variant:
allExceptApple
);
...
...
@@ -1673,6 +1677,7 @@ void main() {
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
10
,
affinity:
TextAffinity
.
upstream
,
));
},
variant:
macOSOnly
);
...
...
@@ -1743,6 +1748,7 @@ void main() {
await
tester
.
pump
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
46
,
// After "to".
affinity:
TextAffinity
.
upstream
,
));
// "good" to "come" is selected.
...
...
@@ -1755,6 +1761,7 @@ void main() {
await
tester
.
pump
();
expect
(
controller
.
selection
,
const
TextSelection
.
collapsed
(
offset:
28
,
// After "good".
affinity:
TextAffinity
.
upstream
,
));
},
variant:
macOSOnly
);
...
...
packages/flutter/test/widgets/editable_text_test.dart
View file @
bcc1dc6b
...
...
@@ -5832,6 +5832,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
3
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -5941,6 +5942,7 @@ void main() {
const
TextSelection
(
baseOffset:
10
,
extentOffset:
10
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6398,6 +6400,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6422,6 +6425,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6464,6 +6468,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6549,6 +6554,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6573,6 +6579,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6615,6 +6622,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6710,6 +6718,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6734,6 +6743,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6776,6 +6786,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6872,6 +6883,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6917,6 +6929,7 @@ void main() {
const
TextSelection
(
baseOffset:
23
,
extentOffset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -6927,6 +6940,7 @@ void main() {
const
TextSelection
(
baseOffset:
23
,
extentOffset:
23
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7060,6 +7074,7 @@ void main() {
controller
.
selection
,
equals
(
const
TextSelection
.
collapsed
(
offset:
4
,
affinity:
TextAffinity
.
upstream
,
)),
);
...
...
@@ -7243,6 +7258,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7266,6 +7282,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7323,6 +7340,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7435,6 +7453,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7458,6 +7477,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7515,6 +7535,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
reason:
'on
$platform
'
,
...
...
@@ -7626,6 +7647,7 @@ void main() {
equals
(
const
TextSelection
.
collapsed
(
offset:
32
,
affinity:
TextAffinity
.
upstream
,
),
),
);
...
...
@@ -10383,7 +10405,6 @@ void main() {
expect
(
controller
.
selection
.
isCollapsed
,
false
);
expect
(
controller
.
selection
.
baseOffset
,
7
);
expect
(
controller
.
selection
.
extentOffset
,
10
);
await
sendKeys
(
tester
,
<
LogicalKeyboardKey
>[
LogicalKeyboardKey
.
arrowLeft
],
...
...
packages/flutter/test/widgets/editable_text_utils.dart
View file @
bcc1dc6b
...
...
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -42,7 +43,7 @@ Offset textOffsetToPosition(WidgetTester tester, int offset) {
renderEditable
,
);
expect
(
endpoints
.
length
,
1
);
return
endpoints
[
0
].
point
+
const
Offset
(
0.0
,
-
2.0
);
return
endpoints
[
0
].
point
+
const
Offset
(
kIsWeb
?
1.0
:
0.0
,
-
2.0
);
}
// Simple controller that builds a WidgetSpan with 100 height.
...
...
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