Merge pull request #2354 from yjbanov/wait-for-pause-on-start
[driver] wait for the isolate to enter pause on start
diff --git a/doc/index.html b/doc/index.html
index 861218c..1db959f 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -51,7 +51,7 @@
<header class="post-header">
</header>
<article class="post-content">
- <p><a href="http://flutter.io">Flutter</a> is a new project to help developers
+ <p>Flutter is a new project to help developers
build high-performance, high-fidelity,
mobile apps for iOS and Android
from a single codebase.
@@ -104,7 +104,7 @@
</svg>
</div>
<ul class="contact-list">
- <li>Flutter</li>
+ <li><a href="https://flutter.io">Flutter</a></li>
</ul>
<p class="terms">
<a href="https://twitter.com/flutterio">@flutterio</a> •
diff --git a/packages/flutter/lib/src/material/icon.dart b/packages/flutter/lib/src/material/icon.dart
index e3ed79d..95c2b0d 100644
--- a/packages/flutter/lib/src/material/icon.dart
+++ b/packages/flutter/lib/src/material/icon.dart
@@ -9,11 +9,24 @@
import 'icon_theme.dart';
import 'theme.dart';
+/// A material design icon.
+///
+/// Available icons are shown on this page:
+/// <https://design.google.com/icons/>
+///
+/// Icons are identified by their name (as given on that page), with
+/// spaces converted to underscores, from the [Icons] class. For
+/// example, the "alarm add" icon is [Icons.alarm_add].
+///
+/// To use this class, make sure you set `uses-material-design: true`
+/// in your project's `flutter.yaml` file. This ensures that the
+/// MaterialIcons font is included in your application. This font is
+/// used to display the icons.
class Icon extends StatelessComponent {
Icon({
Key key,
- this.size: 24.0,
this.icon,
+ this.size: 24.0,
this.color
}) : super(key: key) {
assert(size != null);
@@ -47,21 +60,24 @@
if (icon == null)
return new SizedBox(width: size, height: size);
+ final double iconOpacity = IconTheme.of(context)?.clampedOpacity ?? 1.0;
Color iconColor = color ?? _getDefaultColor(context);
- final int iconAlpha = (255.0 * (IconTheme.of(context)?.clampedOpacity ?? 1.0)).round();
- if (iconAlpha != 255)
- iconColor = color.withAlpha((iconAlpha * color.opacity).round());
+ if (iconOpacity != 1.0)
+ iconColor = iconColor.withAlpha((255.0 * iconColor.opacity * iconOpacity).round());
- return new SizedBox(
- width: size,
- height: size,
- child: new Center(
- child: new Text(new String.fromCharCode(icon.codePoint),
- style: new TextStyle(
- inherit: false,
- color: iconColor,
- fontSize: size,
- fontFamily: 'MaterialIcons'
+ return new ExcludeSemantics(
+ child: new SizedBox(
+ width: size,
+ height: size,
+ child: new Center(
+ child: new Text(
+ new String.fromCharCode(icon.codePoint),
+ style: new TextStyle(
+ inherit: false,
+ color: iconColor,
+ fontSize: size,
+ fontFamily: 'MaterialIcons'
+ )
)
)
)
diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart
index e560d10..794c266 100644
--- a/packages/flutter/lib/src/material/tabs.dart
+++ b/packages/flutter/lib/src/material/tabs.dart
@@ -704,7 +704,8 @@
void _updateScrollBehavior() {
scrollTo(scrollBehavior.updateExtents(
containerExtent: config.scrollDirection == Axis.vertical ? _viewportSize.height : _viewportSize.width,
- contentExtent: _tabWidths.reduce((double sum, double width) => sum + width)
+ contentExtent: _tabWidths.reduce((double sum, double width) => sum + width),
+ scrollOffset: scrollOffset
));
}
@@ -780,7 +781,7 @@
);
if (config.isScrollable) {
- child: new Viewport(
+ return new Viewport(
scrollDirection: Axis.horizontal,
paintOffset: scrollOffsetToPixelDelta(scrollOffset),
onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded,
diff --git a/packages/flutter/lib/src/painting/box_painter.dart b/packages/flutter/lib/src/painting/box_painter.dart
index dce01de..e34b7a7 100644
--- a/packages/flutter/lib/src/painting/box_painter.dart
+++ b/packages/flutter/lib/src/painting/box_painter.dart
@@ -560,6 +560,12 @@
Paint paint = new Paint()..isAntiAlias = false;
if (colorFilter != null)
paint.colorFilter = colorFilter;
+ if (sourceSize != destinationSize) {
+ // Use the "low" quality setting to scale the image, which corresponds to
+ // bilinear interpolation, rather than the default "none" which corresponds
+ // to nearest-neighbor.
+ paint.filterQuality = FilterQuality.low;
+ }
double dx = (outputSize.width - destinationSize.width) * (alignX ?? 0.5);
double dy = (outputSize.height - destinationSize.height) * (alignY ?? 0.5);
Point destinationPosition = rect.topLeft + new Offset(dx, dy);
diff --git a/packages/flutter/test/widget/tabs_test.dart b/packages/flutter/test/widget/tabs_test.dart
index ed1d45d..a8ded32 100644
--- a/packages/flutter/test/widget/tabs_test.dart
+++ b/packages/flutter/test/widget/tabs_test.dart
@@ -7,12 +7,13 @@
import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
-Widget buildFrame({ List<String> tabs, String value, bool isScrollable: false }) {
+Widget buildFrame({ List<String> tabs, String value, bool isScrollable: false, Key tabBarKey }) {
return new Material(
child: new TabBarSelection<String>(
value: value,
values: tabs,
child: new TabBar<String>(
+ key: tabBarKey,
labels: new Map<String, TabLabel>.fromIterable(tabs, value: (String tab) => new TabLabel(text: tab)),
isScrollable: isScrollable
)
@@ -98,4 +99,48 @@
expect(selection.value, equals('A'));
});
});
+
+ test('Scrollable TabBar tap centers selected tab', () {
+ testWidgets((WidgetTester tester) {
+ List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL'];
+ Key tabBarKey = new Key('TabBar');
+ tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey));
+ TabBarSelectionState<String> selection = TabBarSelection.of(tester.findText('AAAAAA'));
+ expect(selection, isNotNull);
+ expect(selection.value, equals('AAAAAA'));
+
+ expect(tester.getSize(tester.findElementByKey(tabBarKey)).width, equals(800.0));
+ // The center of the FFFFFF item is to the right of the TabBar's center
+ expect(tester.getCenter(tester.findText('FFFFFF')).x, greaterThan(401.0));
+
+ tester.tap(tester.findText('FFFFFF'));
+ tester.pump();
+ tester.pump(const Duration(seconds: 1)); // finish the scroll animation
+ expect(selection.value, equals('FFFFFF'));
+ // The center of the FFFFFF item is now at the TabBar's center
+ expect(tester.getCenter(tester.findText('FFFFFF')).x, closeTo(400.0, 1.0));
+ });
+ });
+
+
+ test('TabBar can be scrolled independent of the selection', () {
+ testWidgets((WidgetTester tester) {
+ List<String> tabs = <String>['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL'];
+ Key tabBarKey = new Key('TabBar');
+ tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey));
+ TabBarSelectionState<String> selection = TabBarSelection.of(tester.findText('AAAAAA'));
+ expect(selection, isNotNull);
+ expect(selection.value, equals('AAAAAA'));
+
+ // Fling-scroll the TabBar to the left
+ expect(tester.getCenter(tester.findText('HHHHHH')).x, lessThan(700.0));
+ tester.fling(tester.findElementByKey(tabBarKey), const Offset(-20.0, 0.0), 1000.0);
+ tester.pump();
+ tester.pump(const Duration(seconds: 1)); // finish the scroll animation
+ expect(tester.getCenter(tester.findText('HHHHHH')).x, lessThan(500.0));
+
+ // Scrolling the TabBar doesn't change the selection
+ expect(selection.value, equals('AAAAAA'));
+ });
+ });
}