1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:async'; 6 7import 'package:flutter/cupertino.dart'; 8import 'package:flutter/foundation.dart' show defaultTargetPlatform; 9import 'package:flutter/material.dart'; 10import 'package:flutter/scheduler.dart' show timeDilation; 11import 'package:flutter_gallery/demo/shrine/model/app_state_model.dart'; 12import 'package:scoped_model/scoped_model.dart'; 13 14import 'package:url_launcher/url_launcher.dart'; 15 16import 'demos.dart'; 17import 'home.dart'; 18import 'options.dart'; 19import 'scales.dart'; 20import 'themes.dart'; 21import 'updater.dart'; 22 23class GalleryApp extends StatefulWidget { 24 const GalleryApp({ 25 Key key, 26 this.updateUrlFetcher, 27 this.enablePerformanceOverlay = true, 28 this.enableRasterCacheImagesCheckerboard = true, 29 this.enableOffscreenLayersCheckerboard = true, 30 this.onSendFeedback, 31 this.testMode = false, 32 }) : super(key: key); 33 34 final UpdateUrlFetcher updateUrlFetcher; 35 final bool enablePerformanceOverlay; 36 final bool enableRasterCacheImagesCheckerboard; 37 final bool enableOffscreenLayersCheckerboard; 38 final VoidCallback onSendFeedback; 39 final bool testMode; 40 41 @override 42 _GalleryAppState createState() => _GalleryAppState(); 43} 44 45class _GalleryAppState extends State<GalleryApp> { 46 GalleryOptions _options; 47 Timer _timeDilationTimer; 48 AppStateModel model; 49 50 Map<String, WidgetBuilder> _buildRoutes() { 51 // For a different example of how to set up an application routing table 52 // using named routes, consider the example in the Navigator class documentation: 53 // https://docs.flutter.io/flutter/widgets/Navigator-class.html 54 return Map<String, WidgetBuilder>.fromIterable( 55 kAllGalleryDemos, 56 key: (dynamic demo) => '${demo.routeName}', 57 value: (dynamic demo) => demo.buildRoute, 58 ); 59 } 60 61 @override 62 void initState() { 63 super.initState(); 64 _options = GalleryOptions( 65 themeMode: ThemeMode.system, 66 textScaleFactor: kAllGalleryTextScaleValues[0], 67 timeDilation: timeDilation, 68 platform: defaultTargetPlatform, 69 ); 70 model = AppStateModel()..loadProducts(); 71 } 72 73 @override 74 void dispose() { 75 _timeDilationTimer?.cancel(); 76 _timeDilationTimer = null; 77 super.dispose(); 78 } 79 80 void _handleOptionsChanged(GalleryOptions newOptions) { 81 setState(() { 82 if (_options.timeDilation != newOptions.timeDilation) { 83 _timeDilationTimer?.cancel(); 84 _timeDilationTimer = null; 85 if (newOptions.timeDilation > 1.0) { 86 // We delay the time dilation change long enough that the user can see 87 // that UI has started reacting and then we slam on the brakes so that 88 // they see that the time is in fact now dilated. 89 _timeDilationTimer = Timer(const Duration(milliseconds: 150), () { 90 timeDilation = newOptions.timeDilation; 91 }); 92 } else { 93 timeDilation = newOptions.timeDilation; 94 } 95 } 96 97 _options = newOptions; 98 }); 99 } 100 101 Widget _applyTextScaleFactor(Widget child) { 102 return Builder( 103 builder: (BuildContext context) { 104 return MediaQuery( 105 data: MediaQuery.of(context).copyWith( 106 textScaleFactor: _options.textScaleFactor.scale, 107 ), 108 child: child, 109 ); 110 }, 111 ); 112 } 113 114 @override 115 Widget build(BuildContext context) { 116 Widget home = GalleryHome( 117 testMode: widget.testMode, 118 optionsPage: GalleryOptionsPage( 119 options: _options, 120 onOptionsChanged: _handleOptionsChanged, 121 onSendFeedback: widget.onSendFeedback ?? () { 122 launch('https://github.com/flutter/flutter/issues/new/choose', forceSafariVC: false); 123 }, 124 ), 125 ); 126 127 if (widget.updateUrlFetcher != null) { 128 home = Updater( 129 updateUrlFetcher: widget.updateUrlFetcher, 130 child: home, 131 ); 132 } 133 134 return ScopedModel<AppStateModel>( 135 model: model, 136 child: MaterialApp( 137 theme: kLightGalleryTheme.copyWith(platform: _options.platform), 138 darkTheme: kDarkGalleryTheme.copyWith(platform: _options.platform), 139 themeMode: _options.themeMode, 140 title: 'Flutter Gallery', 141 color: Colors.grey, 142 showPerformanceOverlay: _options.showPerformanceOverlay, 143 checkerboardOffscreenLayers: _options.showOffscreenLayersCheckerboard, 144 checkerboardRasterCacheImages: _options.showRasterCacheImagesCheckerboard, 145 routes: _buildRoutes(), 146 builder: (BuildContext context, Widget child) { 147 return Directionality( 148 textDirection: _options.textDirection, 149 child: _applyTextScaleFactor( 150 // Specifically use a blank Cupertino theme here and do not transfer 151 // over the Material primary color etc except the brightness to 152 // showcase standard iOS looks. 153 Builder(builder: (BuildContext context) { 154 return CupertinoTheme( 155 data: CupertinoThemeData( 156 brightness: Theme.of(context).brightness, 157 ), 158 child: child, 159 ); 160 }), 161 ), 162 ); 163 }, 164 home: home, 165 ), 166 ); 167 } 168} 169