Unverified Commit d188a8ff authored by Hans Muller's avatar Hans Muller Committed by GitHub

Update InputDecorator et al (#13734)

parent c3366a65
...@@ -55,6 +55,7 @@ export 'src/material/icons.dart'; ...@@ -55,6 +55,7 @@ export 'src/material/icons.dart';
export 'src/material/ink_highlight.dart'; export 'src/material/ink_highlight.dart';
export 'src/material/ink_splash.dart'; export 'src/material/ink_splash.dart';
export 'src/material/ink_well.dart'; export 'src/material/ink_well.dart';
export 'src/material/input_border.dart';
export 'src/material/input_decorator.dart'; export 'src/material/input_decorator.dart';
export 'src/material/list_tile.dart'; export 'src/material/list_tile.dart';
export 'src/material/material.dart'; export 'src/material/material.dart';
......
This diff is collapsed.
...@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart'; ...@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart';
import 'feedback.dart'; import 'feedback.dart';
import 'input_decorator.dart'; import 'input_decorator.dart';
import 'material.dart';
import 'text_selection.dart'; import 'text_selection.dart';
import 'theme.dart'; import 'theme.dart';
......
...@@ -285,6 +285,7 @@ class _ShapeDecorationPainter extends BoxPainter { ...@@ -285,6 +285,7 @@ class _ShapeDecorationPainter extends BoxPainter {
final ShapeDecoration _decoration; final ShapeDecoration _decoration;
Rect _lastRect; Rect _lastRect;
TextDirection _lastTextDirection;
Path _outerPath; Path _outerPath;
Path _innerPath; Path _innerPath;
Paint _interiorPaint; Paint _interiorPaint;
...@@ -292,10 +293,11 @@ class _ShapeDecorationPainter extends BoxPainter { ...@@ -292,10 +293,11 @@ class _ShapeDecorationPainter extends BoxPainter {
List<Path> _shadowPaths; List<Path> _shadowPaths;
List<Paint> _shadowPaints; List<Paint> _shadowPaints;
void _precache(Rect rect) { void _precache(Rect rect, TextDirection textDirection) {
assert(rect != null); assert(rect != null);
if (rect == _lastRect) if (rect == _lastRect && textDirection == _lastTextDirection)
return; return;
// We reach here in two cases: // We reach here in two cases:
// - the very first time we paint, in which case everything except _decoration is null // - the very first time we paint, in which case everything except _decoration is null
// - subsequent times, if the rect has changed, in which case we only need to update // - subsequent times, if the rect has changed, in which case we only need to update
...@@ -328,7 +330,9 @@ class _ShapeDecorationPainter extends BoxPainter { ...@@ -328,7 +330,9 @@ class _ShapeDecorationPainter extends BoxPainter {
_outerPath = _decoration.shape.getOuterPath(rect); _outerPath = _decoration.shape.getOuterPath(rect);
if (_decoration.image != null) if (_decoration.image != null)
_innerPath = _decoration.shape.getInnerPath(rect); _innerPath = _decoration.shape.getInnerPath(rect);
_lastRect = rect; _lastRect = rect;
_lastTextDirection = textDirection;
} }
void _paintShadows(Canvas canvas) { void _paintShadows(Canvas canvas) {
...@@ -362,10 +366,11 @@ class _ShapeDecorationPainter extends BoxPainter { ...@@ -362,10 +366,11 @@ class _ShapeDecorationPainter extends BoxPainter {
assert(configuration != null); assert(configuration != null);
assert(configuration.size != null); assert(configuration.size != null);
final Rect rect = offset & configuration.size; final Rect rect = offset & configuration.size;
_precache(rect); final TextDirection textDirection = configuration.textDirection;
_precache(rect, textDirection);
_paintShadows(canvas); _paintShadows(canvas);
_paintInterior(canvas); _paintInterior(canvas);
_paintImage(canvas, configuration); _paintImage(canvas, configuration);
_decoration.shape.paint(canvas, rect); _decoration.shape.paint(canvas, rect, textDirection: textDirection);
} }
} }
...@@ -104,6 +104,15 @@ Future<Null> skipPastScrollingAnimation(WidgetTester tester) async { ...@@ -104,6 +104,15 @@ Future<Null> skipPastScrollingAnimation(WidgetTester tester) async {
await tester.pump(const Duration(milliseconds: 200)); await tester.pump(const Duration(milliseconds: 200));
} }
double getOpacity(WidgetTester tester, Finder finder) {
return tester.widget<Opacity>(
find.ancestor(
of: finder,
matching: find.byType(Opacity),
)
).opacity;
}
void main() { void main() {
final MockClipboard mockClipboard = new MockClipboard(); final MockClipboard mockClipboard = new MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall); SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
...@@ -1006,33 +1015,26 @@ void main() { ...@@ -1006,33 +1015,26 @@ void main() {
); );
// Neither the prefix or the suffix should initially be visible, only the hint. // Neither the prefix or the suffix should initially be visible, only the hint.
expect(find.text('Prefix'), findsNothing); expect(getOpacity(tester, find.text('Prefix')), 0.0);
expect(find.text('Suffix'), findsNothing); expect(getOpacity(tester, find.text('Suffix')), 0.0);
expect(find.text('Hint'), findsOneWidget); expect(getOpacity(tester, find.text('Hint')), 1.0);
await tester.tap(find.byKey(secondKey)); await tester.tap(find.byKey(secondKey));
await tester.pump(); await tester.pumpAndSettle();
// Focus the Input. The hint should display, but not the prefix and suffix. // Focus the Input. The hint, prefix, and suffix should appear
expect(find.text('Prefix'), findsNothing); expect(getOpacity(tester, find.text('Prefix')), 1.0);
expect(find.text('Suffix'), findsNothing); expect(getOpacity(tester, find.text('Suffix')), 1.0);
expect(find.text('Hint'), findsOneWidget); expect(getOpacity(tester, find.text('Hint')), 1.0);
// Enter some text, and the hint should disappear and the prefix and suffix // Enter some text, and the hint should disappear and the prefix and suffix
// should appear. // should continue to be visible
await tester.enterText(find.byKey(secondKey), 'Hi'); await tester.enterText(find.byKey(secondKey), 'Hi');
await tester.pump(); await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Prefix'), findsOneWidget); expect(getOpacity(tester, find.text('Prefix')), 1.0);
expect(find.text('Suffix'), findsOneWidget); expect(getOpacity(tester, find.text('Suffix')), 1.0);
expect(getOpacity(tester, find.text('Hint')), 0.0);
// It's onstage, but animated to zero opacity.
expect(find.text('Hint'), findsOneWidget);
final Element target = tester.element(find.text('Hint'));
final Opacity opacity = target.ancestorWidgetOfExactType(Opacity);
expect(opacity, isNotNull);
expect(opacity.opacity, equals(0.0));
// Check and make sure that the right styles were applied. // Check and make sure that the right styles were applied.
final Text prefixText = tester.widget(find.text('Prefix')); final Text prefixText = tester.widget(find.text('Prefix'));
...@@ -1077,27 +1079,25 @@ void main() { ...@@ -1077,27 +1079,25 @@ void main() {
), ),
); );
// Not focused. The prefix should not display, but the label should. // Not focused. The prefix and suffix should not appear, but the label should.
expect(find.text('Prefix'), findsNothing); expect(getOpacity(tester, find.text('Prefix')), 0.0);
expect(find.text('Suffix'), findsNothing); expect(getOpacity(tester, find.text('Suffix')), 0.0);
expect(find.text('Label'), findsOneWidget); expect(find.text('Label'), findsOneWidget);
// Focus the input. The label, prefix, and suffix should appear.
await tester.tap(find.byKey(secondKey)); await tester.tap(find.byKey(secondKey));
await tester.pump(); await tester.pumpAndSettle();
// Focus the input. The label should display, and also the prefix. expect(getOpacity(tester, find.text('Prefix')), 1.0);
expect(find.text('Prefix'), findsOneWidget); expect(getOpacity(tester, find.text('Suffix')), 1.0);
expect(find.text('Suffix'), findsOneWidget);
expect(find.text('Label'), findsOneWidget); expect(find.text('Label'), findsOneWidget);
// Enter some text, and the label should stay and the prefix should // Enter some text. The label, prefix, and suffix should remain visible.
// remain.
await tester.enterText(find.byKey(secondKey), 'Hi'); await tester.enterText(find.byKey(secondKey), 'Hi');
await tester.pump(); await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Prefix'), findsOneWidget); expect(getOpacity(tester, find.text('Prefix')), 1.0);
expect(find.text('Suffix'), findsOneWidget); expect(getOpacity(tester, find.text('Suffix')), 1.0);
expect(find.text('Label'), findsOneWidget); expect(find.text('Label'), findsOneWidget);
// Check and make sure that the right styles were applied. // Check and make sure that the right styles were applied.
...@@ -1148,21 +1148,25 @@ void main() { ...@@ -1148,21 +1148,25 @@ void main() {
expect(newPos.dy, lessThan(pos.dy)); expect(newPos.dy, lessThan(pos.dy));
}); });
testWidgets('No space between Input icon and text', (WidgetTester tester) async { testWidgets('Icon is separated from input/label by 16+12', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
overlay( overlay(
child: const TextField( child: const TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
icon: const Icon(Icons.phone), icon: const Icon(Icons.phone),
labelText: 'label', labelText: 'label',
filled: true,
), ),
), ),
), ),
); );
final double iconRight = tester.getTopRight(find.byType(Icon)).dx; final double iconRight = tester.getTopRight(find.byType(Icon)).dx;
expect(iconRight, equals(tester.getTopLeft(find.text('label')).dx)); // Per https://material.io/guidelines/components/text-fields.html#text-fields-layout
expect(iconRight, equals(tester.getTopLeft(find.byType(EditableText)).dx)); // There's a 16 dps gap between the right edge of the icon and the text field's
// container, and the 12dps more padding between the left edge of the container
// and the left edge of the input and label.
expect(iconRight + 28.0, equals(tester.getTopLeft(find.text('label')).dx));
expect(iconRight + 28.0, equals(tester.getTopLeft(find.byType(EditableText)).dx));
}); });
testWidgets('Collapsed hint text placement', (WidgetTester tester) async { testWidgets('Collapsed hint text placement', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment