Add large text switching to Gallery app. (#12443)

This lets us preview widgets in the gallery using small, normal, large, and HUGE text.

Added selections to the main drawer for these options. Defaults to "normal", obviously.
This commit is contained in:
Greg Spencer
2017-10-13 21:44:24 -07:00
committed by GitHub
parent c2dfa6a186
commit e697e5523f
6 changed files with 228 additions and 45 deletions

View File

@@ -22,7 +22,7 @@ final List<_Page> _allPages = <_Page>[
new _Page(icon: Icons.android, text: 'ANDROID'),
new _Page(icon: Icons.alarm, text: 'ALARM'),
new _Page(icon: Icons.face, text: 'FACE'),
new _Page(icon: Icons.language, text: 'LANGAUGE'),
new _Page(icon: Icons.language, text: 'LANGUAGE'),
];
class ScrollableTabsDemo extends StatefulWidget {

View File

@@ -12,15 +12,6 @@ import 'home.dart';
import 'item.dart';
import 'updates.dart';
final Map<String, WidgetBuilder> _kRoutes = new Map<String, WidgetBuilder>.fromIterable(
// For a different example of how to set up an application routing table,
// consider the Stocks example:
// https://github.com/flutter/flutter/blob/master/examples/stocks/lib/main.dart
kAllGalleryItems,
key: (GalleryItem item) => item.routeName,
value: (GalleryItem item) => item.buildRoute,
);
final ThemeData _kGalleryLightTheme = new ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
@@ -63,6 +54,9 @@ class GalleryAppState extends State<GalleryApp> {
double _timeDilation = 1.0;
TargetPlatform _platform;
// A null value indicates "use system default".
double _textScaleFactor;
Timer _timeDilationTimer;
@override
@@ -128,6 +122,12 @@ class GalleryAppState extends State<GalleryApp> {
}
});
},
textScaleFactor: _textScaleFactor,
onTextScaleFactorChanged: (double value) {
setState(() {
_textScaleFactor = value;
});
},
onSendFeedback: widget.onSendFeedback,
);
@@ -138,6 +138,33 @@ class GalleryAppState extends State<GalleryApp> {
);
}
final Map<String, WidgetBuilder> _kRoutes = new Map<String,
WidgetBuilder>.fromIterable(
// For a different example of how to set up an application routing table
// using named routes, consider the example in the Navigator class documentation:
// https://docs.flutter.io/flutter/widgets/Navigator-class.html
kAllGalleryItems,
key: (GalleryItem item) => item.routeName,
value: (GalleryItem item) =>
(BuildContext context) {
if (_textScaleFactor != null) {
return new MediaQuery(
data: new MediaQueryData(textScaleFactor: _textScaleFactor),
child: item.buildRoute(context),
);
} else {
return item.buildRoute(context);
}
}
);
if (_textScaleFactor != null) {
home = new MediaQuery(
data: new MediaQueryData(textScaleFactor: _textScaleFactor),
child: home,
);
}
return new MaterialApp(
title: 'Flutter Gallery',
color: Colors.grey,

View File

@@ -108,6 +108,8 @@ class GalleryDrawer extends StatelessWidget {
@required this.onThemeChanged,
this.timeDilation,
@required this.onTimeDilationChanged,
this.textScaleFactor,
this.onTextScaleFactorChanged,
this.showPerformanceOverlay,
this.onShowPerformanceOverlayChanged,
this.checkerboardRasterCacheImages,
@@ -126,6 +128,9 @@ class GalleryDrawer extends StatelessWidget {
final double timeDilation;
final ValueChanged<double> onTimeDilationChanged;
final double textScaleFactor;
final ValueChanged<double> onTextScaleFactorChanged;
final bool showPerformanceOverlay;
final ValueChanged<bool> onShowPerformanceOverlayChanged;
@@ -183,6 +188,25 @@ class GalleryDrawer extends StatelessWidget {
selected: Theme.of(context).platform == TargetPlatform.iOS,
);
final List<Widget> textSizeItems = <Widget>[];
final Map<double, String> textSizes = <double, String>{
null: 'System Default',
0.8: 'Small',
1.0: 'Normal',
1.3: 'Large',
2.0: 'Huge',
};
for (double size in textSizes.keys) {
textSizeItems.add(new RadioListTile<double>(
secondary: const Icon(Icons.text_fields),
title: new Text(textSizes[size]),
value: size,
groupValue: textScaleFactor,
onChanged: onTextScaleFactorChanged,
selected: textScaleFactor == size,
));
}
final Widget animateSlowlyItem = new CheckboxListTile(
title: const Text('Animate Slowly'),
value: timeDilation != 1.0,
@@ -214,11 +238,11 @@ class GalleryDrawer extends StatelessWidget {
children: <TextSpan>[
new TextSpan(
style: aboutTextStyle,
text: "Flutter is an early-stage, open-source project to help "
"developers build high-performance, high-fidelity, mobile "
"apps for iOS and Android from a single codebase. This "
"gallery is a preview of Flutter's many widgets, behaviors, "
"animations, layouts, and more. Learn more about Flutter at "
text: 'Flutter is an early-stage, open-source project to help '
'developers build high-performance, high-fidelity, mobile '
'apps for iOS and Android from a single codebase. This '
"gallery is a preview of Flutter's many widgets, behaviors, "
'animations, layouts, and more. Learn more about Flutter at '
),
new LinkTextSpan(
style: linkStyle,
@@ -226,7 +250,7 @@ class GalleryDrawer extends StatelessWidget {
),
new TextSpan(
style: aboutTextStyle,
text: ".\n\nTo see the source code for this app, please visit the "
text: '.\n\nTo see the source code for this app, please visit the '
),
new LinkTextSpan(
style: linkStyle,
@@ -235,7 +259,7 @@ class GalleryDrawer extends StatelessWidget {
),
new TextSpan(
style: aboutTextStyle,
text: "."
text: '.'
)
]
)
@@ -252,42 +276,58 @@ class GalleryDrawer extends StatelessWidget {
mountainViewItem,
cupertinoItem,
const Divider(),
animateSlowlyItem,
// index 8, optional: Performance Overlay
sendFeedbackItem,
aboutItem
];
if (onShowPerformanceOverlayChanged != null) {
allDrawerItems.insert(8, new CheckboxListTile(
title: const Text('Performance Overlay'),
value: showPerformanceOverlay,
onChanged: onShowPerformanceOverlayChanged,
secondary: const Icon(Icons.assessment),
selected: showPerformanceOverlay,
));
}
allDrawerItems.addAll(textSizeItems);
if (onCheckerboardRasterCacheImagesChanged != null) {
allDrawerItems.insert(8, new CheckboxListTile(
title: const Text('Checkerboard Raster Cache Images'),
value: checkerboardRasterCacheImages,
onChanged: onCheckerboardRasterCacheImagesChanged,
secondary: const Icon(Icons.assessment),
selected: checkerboardRasterCacheImages,
));
}
allDrawerItems..addAll(<Widget>[
const Divider(),
animateSlowlyItem,
const Divider(),
]);
bool addedOptionalItem = false;
if (onCheckerboardOffscreenLayersChanged != null) {
allDrawerItems.insert(8, new CheckboxListTile(
allDrawerItems.add(new CheckboxListTile(
title: const Text('Checkerboard Offscreen Layers'),
value: checkerboardOffscreenLayers,
onChanged: onCheckerboardOffscreenLayersChanged,
secondary: const Icon(Icons.assessment),
selected: checkerboardOffscreenLayers,
));
addedOptionalItem = true;
}
if (onCheckerboardRasterCacheImagesChanged != null) {
allDrawerItems.add(new CheckboxListTile(
title: const Text('Checkerboard Raster Cache Images'),
value: checkerboardRasterCacheImages,
onChanged: onCheckerboardRasterCacheImagesChanged,
secondary: const Icon(Icons.assessment),
selected: checkerboardRasterCacheImages,
));
addedOptionalItem = true;
}
if (onShowPerformanceOverlayChanged != null) {
allDrawerItems.add(new CheckboxListTile(
title: const Text('Performance Overlay'),
value: showPerformanceOverlay,
onChanged: onShowPerformanceOverlayChanged,
secondary: const Icon(Icons.assessment),
selected: showPerformanceOverlay,
));
addedOptionalItem = true;
}
if (addedOptionalItem)
allDrawerItems.add(const Divider());
allDrawerItems.addAll(<Widget>[
sendFeedbackItem,
aboutItem,
]);
return new Drawer(child: new ListView(primary: false, children: allDrawerItems));
}
}

View File

@@ -68,6 +68,8 @@ class GalleryHome extends StatefulWidget {
@required this.onThemeChanged,
this.timeDilation,
@required this.onTimeDilationChanged,
this.textScaleFactor,
this.onTextScaleFactorChanged,
this.showPerformanceOverlay,
this.onShowPerformanceOverlayChanged,
this.checkerboardRasterCacheImages,
@@ -86,6 +88,9 @@ class GalleryHome extends StatefulWidget {
final double timeDilation;
final ValueChanged<double> onTimeDilationChanged;
final double textScaleFactor;
final ValueChanged<double> onTextScaleFactorChanged;
final bool showPerformanceOverlay;
final ValueChanged<bool> onShowPerformanceOverlayChanged;
@@ -159,6 +164,8 @@ class GalleryHomeState extends State<GalleryHome> with SingleTickerProviderState
onThemeChanged: widget.onThemeChanged,
timeDilation: widget.timeDilation,
onTimeDilationChanged: widget.onTimeDilationChanged,
textScaleFactor: widget.textScaleFactor,
onTextScaleFactorChanged: widget.onTextScaleFactorChanged,
showPerformanceOverlay: widget.showPerformanceOverlay,
onShowPerformanceOverlayChanged: widget.onShowPerformanceOverlayChanged,
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,

View File

@@ -0,0 +1,100 @@
// Copyright 2017 The Chromium 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/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_gallery/gallery/app.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
testWidgets('Flutter Gallery drawer item test', (WidgetTester tester) async {
bool hasFeedback = false;
void mockOnSendFeedback() {
hasFeedback = true;
}
await tester.pumpWidget(new GalleryApp(onSendFeedback: mockOnSendFeedback));
await tester.pump(); // see https://github.com/flutter/flutter/issues/1865
await tester.pump(); // triggers a frame
final Finder finder = find.byWidgetPredicate((Widget widget) {
return widget is Tooltip && widget.message == 'Open navigation menu';
});
expect(finder, findsOneWidget);
// Open drawer
await tester.tap(finder);
await tester.pump(); // start animation
await tester.pump(const Duration(seconds: 1)); // end animation
MaterialApp app = find.byType(MaterialApp).evaluate().first.widget;
expect(app.theme.brightness, equals(Brightness.light));
// Change theme
await tester.tap(find.text('Dark'));
await tester.pump(); // start animation
await tester.pump(const Duration(seconds: 1)); // end animation
app = find.byType(MaterialApp).evaluate().first.widget;
expect(app.theme.brightness, equals(Brightness.dark));
expect(app.theme.platform, equals(TargetPlatform.android));
// Change platform
await tester.tap(find.text('iOS'));
await tester.pump(); // start animation
await tester.pump(const Duration(seconds: 1)); // end animation
app = find.byType(MaterialApp).evaluate().first.widget;
expect(app.theme.platform, equals(TargetPlatform.iOS));
// Verify the font scale.
final Size origTextSize = tester.getSize(find.text("Small"));
expect(origTextSize, equals(const Size(176.0, 14.0)));
// Switch font scale.
await tester.tap(find.text('Small'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
final Size textSize = tester.getSize(find.text("Small"));
expect(textSize, equals(const Size(176.0, 11.0)));
// Set font scale back to default.
await tester.tap(find.text('System Default'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
final Size newTextSize = tester.getSize(find.text("Small"));
expect(newTextSize, equals(origTextSize));
// Scroll to the bottom of the menu.
await tester.drag(find.text('Small'), const Offset(0.0, -450.0));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// Test slow animations.
expect(timeDilation, equals(1.0));
await tester.tap(find.text('Animate Slowly'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
expect(timeDilation, greaterThan(1.0));
// Put back time dilation (so as not to throw off tests after this one).
await tester.tap(find.text('Animate Slowly'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
expect(timeDilation, equals(1.0));
// Send feedback.
expect(hasFeedback, false);
await tester.tap(find.text('Send feedback'));
await tester.pump();
expect(hasFeedback, true);
// Close drawer
await tester.tap(find.byType(DrawerController));
await tester.pump(); // start animation
await tester.pump(const Duration(seconds: 1)); // end animation
});
}

View File

@@ -139,22 +139,31 @@ Future<Null> runSmokeTest(WidgetTester tester) async {
await tester.pump(); // Start opening drawer.
await tester.pump(const Duration(seconds: 1)); // Wait until it's really opened.
// switch theme
// Switch theme.
await tester.tap(find.text('Dark'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// switch theme
// Switch theme.
await tester.tap(find.text('Light'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// scroll the 'Send feedback' item into view
await tester.drag(find.text('Light'), const Offset(0.0, -200.0));
// Switch font scale.
await tester.tap(find.text('Small'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// Switch font scale back to default.
await tester.tap(find.text('System Default'));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// send feedback
// Scroll the 'Send feedback' item into view.
await tester.drag(find.text('Small'), const Offset(0.0, -450.0));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// Send feedback.
expect(hasFeedback, false);
await tester.tap(find.text('Send feedback'));
await tester.pump();