Unverified Commit 5c2259d5 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Cross fade gallery UI front layer (#17064)

parent 7a0ebad0
...@@ -46,7 +46,7 @@ const String _actionText = ...@@ -46,7 +46,7 @@ const String _actionText =
const String _actionCode = 'buttons_action'; const String _actionCode = 'buttons_action';
class ButtonsDemo extends StatefulWidget { class ButtonsDemo extends StatefulWidget {
static const String routeName = '/material//buttons'; static const String routeName = '/material/buttons';
@override @override
_ButtonsDemoState createState() => new _ButtonsDemoState(); _ButtonsDemoState createState() => new _ButtonsDemoState();
......
...@@ -45,30 +45,10 @@ class _GalleryAppState extends State<GalleryApp> { ...@@ -45,30 +45,10 @@ class _GalleryAppState extends State<GalleryApp> {
// For a different example of how to set up an application routing table // For a different example of how to set up an application routing table
// using named routes, consider the example in the Navigator class documentation: // using named routes, consider the example in the Navigator class documentation:
// https://docs.flutter.io/flutter/widgets/Navigator-class.html // https://docs.flutter.io/flutter/widgets/Navigator-class.html
return new Map<String, WidgetBuilder>.fromIterable( return new Map<String, WidgetBuilder>.fromIterable(
kAllGalleryDemos, kAllGalleryDemos,
key: (dynamic demo) => '${demo.routeName}', key: (dynamic demo) => '${demo.routeName}',
value: (dynamic demo) => demo.buildRoute, value: (dynamic demo) => demo.buildRoute,
)..addAll(
new Map<String, WidgetBuilder>.fromIterable(
kAllGalleryDemoCategories,
key: (dynamic category) => '/${category.name}',
value: (dynamic category) {
return (BuildContext context) {
return new DemosPage(
category: category,
optionsPage: new GalleryOptionsPage(
options: _options,
onOptionsChanged: _handleOptionsChanged,
onSendFeedback: widget.onSendFeedback ?? () {
launch('https://github.com/flutter/flutter/issues/new', forceSafariVC: false);
},
),
);
};
},
),
); );
} }
...@@ -131,7 +111,7 @@ class _GalleryAppState extends State<GalleryApp> { ...@@ -131,7 +111,7 @@ class _GalleryAppState extends State<GalleryApp> {
options: _options, options: _options,
onOptionsChanged: _handleOptionsChanged, onOptionsChanged: _handleOptionsChanged,
onSendFeedback: widget.onSendFeedback ?? () { onSendFeedback: widget.onSendFeedback ?? () {
launch('https://github.com/flutter/flutter/issues/new'); launch('https://github.com/flutter/flutter/issues/new', forceSafariVC: false);
}, },
), ),
); );
......
...@@ -115,7 +115,7 @@ class _CrossFadeTransition extends AnimatedWidget { ...@@ -115,7 +115,7 @@ class _CrossFadeTransition extends AnimatedWidget {
), ),
), ),
new IgnorePointer( new IgnorePointer(
ignoring: opacity2 <1.0, ignoring: opacity2 < 1.0,
child: new Opacity( child: new Opacity(
opacity: opacity2, opacity: opacity2,
child: new Semantics( child: new Semantics(
......
...@@ -13,6 +13,7 @@ import 'demos.dart'; ...@@ -13,6 +13,7 @@ import 'demos.dart';
const String _kGalleryAssetsPackage = 'flutter_gallery_assets'; const String _kGalleryAssetsPackage = 'flutter_gallery_assets';
const Color _kFlutterBlue = const Color(0xFF003D75); const Color _kFlutterBlue = const Color(0xFF003D75);
const double _kDemoItemHeight = 64.0; const double _kDemoItemHeight = 64.0;
const Duration _kFrontLayerSwitchDuration = const Duration(milliseconds: 300);
class _FlutterLogo extends StatelessWidget { class _FlutterLogo extends StatelessWidget {
const _FlutterLogo({ Key key }) : super(key: key); const _FlutterLogo({ Key key }) : super(key: key);
...@@ -104,6 +105,7 @@ class _CategoriesPage extends StatelessWidget { ...@@ -104,6 +105,7 @@ class _CategoriesPage extends StatelessWidget {
final int columnCount = (MediaQuery.of(context).orientation == Orientation.portrait) ? 2 : 3; final int columnCount = (MediaQuery.of(context).orientation == Orientation.portrait) ? 2 : 3;
return new SingleChildScrollView( return new SingleChildScrollView(
key: const PageStorageKey<String>('categories'),
child: new LayoutBuilder( child: new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) { builder: (BuildContext context, BoxConstraints constraints) {
final double columnWidth = constraints.biggest.width / columnCount.toDouble(); final double columnWidth = constraints.biggest.width / columnCount.toDouble();
...@@ -130,7 +132,7 @@ class _CategoriesPage extends StatelessWidget { ...@@ -130,7 +132,7 @@ class _CategoriesPage extends StatelessWidget {
child: new _CategoryItem( child: new _CategoryItem(
category: category, category: category,
onTap: () { onTap: () {
Navigator.pushNamed(context, '/${category.name}'); onCategoryTap(category);
}, },
), ),
); );
...@@ -213,51 +215,21 @@ class _DemoItem extends StatelessWidget { ...@@ -213,51 +215,21 @@ class _DemoItem extends StatelessWidget {
} }
} }
class DemosPage extends StatelessWidget { class _DemosPage extends StatelessWidget {
const DemosPage({ const _DemosPage(this.category);
Key key,
this.category,
this.optionsPage,
}) : super(key: key);
final GalleryDemoCategory category; final GalleryDemoCategory category;
final Widget optionsPage;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context); return new KeyedSubtree(
final bool isDark = theme.brightness == Brightness.dark; key: const ValueKey<String>('GalleryDemoList'), // So the tests can find this ListView
child: new ListView(
return new Scaffold( key: new PageStorageKey<String>(category.name),
backgroundColor: isDark ? _kFlutterBlue : theme.primaryColor, padding: const EdgeInsets.only(top: 8.0),
body: new SafeArea( children: kGalleryCategoryToDemos[category].map<Widget>((GalleryDemo demo) {
child: new SizedBox.expand( return new _DemoItem(demo: demo);
child: new Backdrop( }).toList(),
backTitle: const Text('Options'),
backLayer: optionsPage,
frontAction: const BackButton(),
frontTitle: new Text(category.name),
frontHeading: new Container(
height: 40.0,
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: const Divider(
color: const Color(0xFFD5D7DA),
height: 1.0
),
),
frontLayer: new Padding(
padding: const EdgeInsets.only(top: 40.0),
child: new ListView(
key: const ValueKey<String>('GalleryDemoList'), // So tests can find it.
padding: const EdgeInsets.only(top: 8.0),
children: kGalleryCategoryToDemos[category].map<Widget>((GalleryDemo demo) {
return new _DemoItem(demo: demo);
}).toList(),
),
),
),
),
), ),
); );
} }
...@@ -282,6 +254,7 @@ class GalleryHome extends StatefulWidget { ...@@ -282,6 +254,7 @@ class GalleryHome extends StatefulWidget {
class _GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin { class _GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStateMixin {
static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); static final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
AnimationController _controller; AnimationController _controller;
GalleryDemoCategory _category;
@override @override
void initState() { void initState() {
...@@ -312,11 +285,39 @@ class _GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStat ...@@ -312,11 +285,39 @@ class _GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStat
child: new Backdrop( child: new Backdrop(
backTitle: const Text('Options'), backTitle: const Text('Options'),
backLayer: widget.optionsPage, backLayer: widget.optionsPage,
frontAction: const _FlutterLogo(), frontAction: new AnimatedSwitcher(
frontTitle: const Text('Flutter gallery'), duration: _kFrontLayerSwitchDuration,
child: _category == null
? const _FlutterLogo()
: new IconButton(
icon: const BackButtonIcon(),
tooltip: 'Back',
onPressed: () {
setState(() {
_category = null;
});
},
),
),
frontTitle: new AnimatedSwitcher(
duration: _kFrontLayerSwitchDuration,
child: _category == null
? const Text('Flutter gallery')
: new Text(_category.name),
),
frontHeading: new Container(height: 24.0), frontHeading: new Container(height: 24.0),
frontLayer: new _CategoriesPage( frontLayer: new AnimatedSwitcher(
categories: kAllGalleryDemoCategories, duration: _kFrontLayerSwitchDuration,
child: _category != null
? new _DemosPage(_category)
: new _CategoriesPage(
categories: kAllGalleryDemoCategories,
onCategoryTap: (GalleryDemoCategory category) {
setState(() {
_category = category;
});
},
),
), ),
), ),
), ),
......
...@@ -18,7 +18,7 @@ void main() { ...@@ -18,7 +18,7 @@ void main() {
await tester.pump(); // see https://github.com/flutter/flutter/issues/1865 await tester.pump(); // see https://github.com/flutter/flutter/issues/1865
await tester.pump(); // triggers a frame await tester.pump(); // triggers a frame
Scrollable.ensureVisible(tester.element(find.text('Material')), alignment: 0.5); await Scrollable.ensureVisible(tester.element(find.text('Material')), alignment: 0.5);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.text('Material')); await tester.tap(find.text('Material'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
......
...@@ -150,10 +150,11 @@ Future<Null> smokeGallery(WidgetTester tester) async { ...@@ -150,10 +150,11 @@ Future<Null> smokeGallery(WidgetTester tester) async {
expect(find.text(kGalleryTitle), findsOneWidget); expect(find.text(kGalleryTitle), findsOneWidget);
for (GalleryDemoCategory category in kAllGalleryDemoCategories) { for (GalleryDemoCategory category in kAllGalleryDemoCategories) {
await Scrollable.ensureVisible(tester.element(find.text(category.name)), alignment: 0.5);
await tester.tap(find.text(category.name)); await tester.tap(find.text(category.name));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
for (GalleryDemo demo in kGalleryCategoryToDemos[category]) { for (GalleryDemo demo in kGalleryCategoryToDemos[category]) {
Scrollable.ensureVisible(tester.element(find.text(demo.title)), alignment: 0.5); await Scrollable.ensureVisible(tester.element(find.text(demo.title)), alignment: 0.0);
await smokeDemo(tester, demo); await smokeDemo(tester, demo);
tester.binding.debugAssertNoTransientCallbacks('A transient callback was still active after running $demo'); tester.binding.debugAssertNoTransientCallbacks('A transient callback was still active after running $demo');
} }
......
...@@ -126,12 +126,15 @@ Future<Null> runDemos(List<String> demos, FlutterDriver driver) async { ...@@ -126,12 +126,15 @@ Future<Null> runDemos(List<String> demos, FlutterDriver driver) async {
for (String demo in demos) { for (String demo in demos) {
final String demoAtCategory = _allDemos.firstWhere((String s) => s.startsWith(demo)); final String demoAtCategory = _allDemos.firstWhere((String s) => s.startsWith(demo));
final String demoCategory = demoAtCategory.substring(demoAtCategory.indexOf('@') + 1); final String demoCategory = demoAtCategory.substring(demoAtCategory.indexOf('@') + 1);
print('> $demoAtCategory');
if (currentDemoCategory == null) { if (currentDemoCategory == null) {
await driver.tap(find.text(demoCategory)); await driver.tap(find.text(demoCategory));
} else if (currentDemoCategory != demoCategory) { } else if (currentDemoCategory != demoCategory) {
await driver.tap(find.byTooltip('Back')); await driver.tap(find.byTooltip('Back'));
await driver.tap(find.text(demoCategory)); await driver.tap(find.text(demoCategory));
// Scroll back to the top
await driver.scroll(demoList, 0.0, 10000.0, const Duration(milliseconds: 100));
} }
currentDemoCategory = demoCategory; currentDemoCategory = demoCategory;
...@@ -150,7 +153,7 @@ Future<Null> runDemos(List<String> demos, FlutterDriver driver) async { ...@@ -150,7 +153,7 @@ Future<Null> runDemos(List<String> demos, FlutterDriver driver) async {
} }
} }
print('Success'); print('< Success');
} }
// Return to the home screen // Return to the home screen
......
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