• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 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 'package:flutter/material.dart';
6
7import '../demo/all.dart';
8import 'icons.dart';
9
10class GalleryDemoCategory {
11  const GalleryDemoCategory._({
12    @required this.name,
13    @required this.icon,
14  });
15
16  final String name;
17  final IconData icon;
18
19  @override
20  bool operator ==(dynamic other) {
21    if (identical(this, other))
22      return true;
23    if (runtimeType != other.runtimeType)
24      return false;
25    final GalleryDemoCategory typedOther = other;
26    return typedOther.name == name && typedOther.icon == icon;
27  }
28
29  @override
30  int get hashCode => hashValues(name, icon);
31
32  @override
33  String toString() {
34    return '$runtimeType($name)';
35  }
36}
37
38const GalleryDemoCategory _kDemos = GalleryDemoCategory._(
39  name: 'Studies',
40  icon: GalleryIcons.animation,
41);
42
43const GalleryDemoCategory _kStyle = GalleryDemoCategory._(
44  name: 'Style',
45  icon: GalleryIcons.custom_typography,
46);
47
48const GalleryDemoCategory _kMaterialComponents = GalleryDemoCategory._(
49  name: 'Material',
50  icon: GalleryIcons.category_mdc,
51);
52
53const GalleryDemoCategory _kCupertinoComponents = GalleryDemoCategory._(
54  name: 'Cupertino',
55  icon: GalleryIcons.phone_iphone,
56);
57
58const GalleryDemoCategory _kMedia = GalleryDemoCategory._(
59  name: 'Media',
60  icon: GalleryIcons.drive_video,
61);
62
63class GalleryDemo {
64  const GalleryDemo({
65    @required this.title,
66    @required this.icon,
67    this.subtitle,
68    @required this.category,
69    @required this.routeName,
70    this.documentationUrl,
71    @required this.buildRoute,
72  }) : assert(title != null),
73       assert(category != null),
74       assert(routeName != null),
75       assert(buildRoute != null);
76
77  final String title;
78  final IconData icon;
79  final String subtitle;
80  final GalleryDemoCategory category;
81  final String routeName;
82  final WidgetBuilder buildRoute;
83  final String documentationUrl;
84
85  @override
86  String toString() {
87    return '$runtimeType($title $routeName)';
88  }
89}
90
91List<GalleryDemo> _buildGalleryDemos() {
92  final List<GalleryDemo> galleryDemos = <GalleryDemo>[
93    // Demos
94    GalleryDemo(
95      title: 'Shrine',
96      subtitle: 'Basic shopping app',
97      icon: GalleryIcons.shrine,
98      category: _kDemos,
99      routeName: ShrineDemo.routeName,
100      buildRoute: (BuildContext context) => const ShrineDemo(),
101    ),
102    GalleryDemo(
103      title: 'Fortnightly',
104      subtitle: 'Newspaper typography app',
105      icon: GalleryIcons.custom_typography,
106      category: _kDemos,
107      routeName: FortnightlyDemo.routeName,
108      buildRoute: (BuildContext context) => FortnightlyDemo(),
109    ),
110    GalleryDemo(
111      title: 'Contact profile',
112      subtitle: 'Address book entry with a flexible appbar',
113      icon: GalleryIcons.account_box,
114      category: _kDemos,
115      routeName: ContactsDemo.routeName,
116      buildRoute: (BuildContext context) => ContactsDemo(),
117    ),
118    GalleryDemo(
119      title: 'Animation',
120      subtitle: 'Section organizer',
121      icon: GalleryIcons.animation,
122      category: _kDemos,
123      routeName: AnimationDemo.routeName,
124      buildRoute: (BuildContext context) => const AnimationDemo(),
125    ),
126    GalleryDemo(
127      title: '2D Transformations',
128      subtitle: 'Pan, Zoom, Rotate',
129      icon: GalleryIcons.grid_on,
130      category: _kDemos,
131      routeName: TransformationsDemo.routeName,
132      buildRoute: (BuildContext context) => const TransformationsDemo(),
133    ),
134
135    // Style
136    GalleryDemo(
137      title: 'Colors',
138      subtitle: 'All of the predefined colors',
139      icon: GalleryIcons.colors,
140      category: _kStyle,
141      routeName: ColorsDemo.routeName,
142      buildRoute: (BuildContext context) => ColorsDemo(),
143    ),
144    GalleryDemo(
145      title: 'Typography',
146      subtitle: 'All of the predefined text styles',
147      icon: GalleryIcons.custom_typography,
148      category: _kStyle,
149      routeName: TypographyDemo.routeName,
150      buildRoute: (BuildContext context) => TypographyDemo(),
151    ),
152
153    // Material Components
154    GalleryDemo(
155      title: 'Backdrop',
156      subtitle: 'Select a front layer from back layer',
157      icon: GalleryIcons.backdrop,
158      category: _kMaterialComponents,
159      routeName: BackdropDemo.routeName,
160      buildRoute: (BuildContext context) => BackdropDemo(),
161    ),
162    GalleryDemo(
163      title: 'Banner',
164      subtitle: 'Displaying a banner within a list',
165      icon: GalleryIcons.lists_leave_behind,
166      category: _kMaterialComponents,
167      routeName: BannerDemo.routeName,
168      documentationUrl: 'https://api.flutter.dev/flutter/material/MaterialBanner-class.html',
169      buildRoute: (BuildContext context) => const BannerDemo(),
170    ),
171    GalleryDemo(
172      title: 'Bottom app bar',
173      subtitle: 'Optional floating action button notch',
174      icon: GalleryIcons.bottom_app_bar,
175      category: _kMaterialComponents,
176      routeName: BottomAppBarDemo.routeName,
177      documentationUrl: 'https://docs.flutter.io/flutter/material/BottomAppBar-class.html',
178      buildRoute: (BuildContext context) => BottomAppBarDemo(),
179    ),
180    GalleryDemo(
181      title: 'Bottom navigation',
182      subtitle: 'Bottom navigation with cross-fading views',
183      icon: GalleryIcons.bottom_navigation,
184      category: _kMaterialComponents,
185      routeName: BottomNavigationDemo.routeName,
186      documentationUrl: 'https://docs.flutter.io/flutter/material/BottomNavigationBar-class.html',
187      buildRoute: (BuildContext context) => BottomNavigationDemo(),
188    ),
189    GalleryDemo(
190      title: 'Bottom sheet: Modal',
191      subtitle: 'A dismissible bottom sheet',
192      icon: GalleryIcons.bottom_sheets,
193      category: _kMaterialComponents,
194      routeName: ModalBottomSheetDemo.routeName,
195      documentationUrl: 'https://docs.flutter.io/flutter/material/showModalBottomSheet.html',
196      buildRoute: (BuildContext context) => ModalBottomSheetDemo(),
197    ),
198    GalleryDemo(
199      title: 'Bottom sheet: Persistent',
200      subtitle: 'A bottom sheet that sticks around',
201      icon: GalleryIcons.bottom_sheet_persistent,
202      category: _kMaterialComponents,
203      routeName: PersistentBottomSheetDemo.routeName,
204      documentationUrl: 'https://docs.flutter.io/flutter/material/ScaffoldState/showBottomSheet.html',
205      buildRoute: (BuildContext context) => PersistentBottomSheetDemo(),
206    ),
207    GalleryDemo(
208      title: 'Buttons',
209      subtitle: 'Flat, raised, dropdown, and more',
210      icon: GalleryIcons.generic_buttons,
211      category: _kMaterialComponents,
212      routeName: ButtonsDemo.routeName,
213      buildRoute: (BuildContext context) => ButtonsDemo(),
214    ),
215    GalleryDemo(
216      title: 'Buttons: Floating Action Button',
217      subtitle: 'FAB with transitions',
218      icon: GalleryIcons.buttons,
219      category: _kMaterialComponents,
220      routeName: TabsFabDemo.routeName,
221      documentationUrl: 'https://docs.flutter.io/flutter/material/FloatingActionButton-class.html',
222      buildRoute: (BuildContext context) => TabsFabDemo(),
223    ),
224    GalleryDemo(
225      title: 'Cards',
226      subtitle: 'Baseline cards with rounded corners',
227      icon: GalleryIcons.cards,
228      category: _kMaterialComponents,
229      routeName: CardsDemo.routeName,
230      documentationUrl: 'https://docs.flutter.io/flutter/material/Card-class.html',
231      buildRoute: (BuildContext context) => CardsDemo(),
232    ),
233    GalleryDemo(
234      title: 'Chips',
235      subtitle: 'Labeled with delete buttons and avatars',
236      icon: GalleryIcons.chips,
237      category: _kMaterialComponents,
238      routeName: ChipDemo.routeName,
239      documentationUrl: 'https://docs.flutter.io/flutter/material/Chip-class.html',
240      buildRoute: (BuildContext context) => ChipDemo(),
241    ),
242    GalleryDemo(
243      title: 'Data tables',
244      subtitle: 'Rows and columns',
245      icon: GalleryIcons.data_table,
246      category: _kMaterialComponents,
247      routeName: DataTableDemo.routeName,
248      documentationUrl: 'https://docs.flutter.io/flutter/material/PaginatedDataTable-class.html',
249      buildRoute: (BuildContext context) => DataTableDemo(),
250    ),
251    GalleryDemo(
252      title: 'Dialogs',
253      subtitle: 'Simple, alert, and fullscreen',
254      icon: GalleryIcons.dialogs,
255      category: _kMaterialComponents,
256      routeName: DialogDemo.routeName,
257      documentationUrl: 'https://docs.flutter.io/flutter/material/showDialog.html',
258      buildRoute: (BuildContext context) => DialogDemo(),
259    ),
260    GalleryDemo(
261      title: 'Elevations',
262      subtitle: 'Shadow values on cards',
263      // TODO(larche): Change to custom icon for elevations when one exists.
264      icon: GalleryIcons.cupertino_progress,
265      category: _kMaterialComponents,
266      routeName: ElevationDemo.routeName,
267      documentationUrl: 'https://docs.flutter.io/flutter/material/Material/elevation.html',
268      buildRoute: (BuildContext context) => ElevationDemo(),
269    ),
270    GalleryDemo(
271      title: 'Expand/collapse list control',
272      subtitle: 'A list with one sub-list level',
273      icon: GalleryIcons.expand_all,
274      category: _kMaterialComponents,
275      routeName: ExpansionTileListDemo.routeName,
276      documentationUrl: 'https://docs.flutter.io/flutter/material/ExpansionTile-class.html',
277      buildRoute: (BuildContext context) => ExpansionTileListDemo(),
278    ),
279    GalleryDemo(
280      title: 'Expansion panels',
281      subtitle: 'List of expanding panels',
282      icon: GalleryIcons.expand_all,
283      category: _kMaterialComponents,
284      routeName: ExpansionPanelsDemo.routeName,
285      documentationUrl: 'https://docs.flutter.io/flutter/material/ExpansionPanel-class.html',
286      buildRoute: (BuildContext context) => ExpansionPanelsDemo(),
287    ),
288    GalleryDemo(
289      title: 'Grid',
290      subtitle: 'Row and column layout',
291      icon: GalleryIcons.grid_on,
292      category: _kMaterialComponents,
293      routeName: GridListDemo.routeName,
294      documentationUrl: 'https://docs.flutter.io/flutter/widgets/GridView-class.html',
295      buildRoute: (BuildContext context) => const GridListDemo(),
296    ),
297    GalleryDemo(
298      title: 'Icons',
299      subtitle: 'Enabled and disabled icons with opacity',
300      icon: GalleryIcons.sentiment_very_satisfied,
301      category: _kMaterialComponents,
302      routeName: IconsDemo.routeName,
303      documentationUrl: 'https://docs.flutter.io/flutter/material/IconButton-class.html',
304      buildRoute: (BuildContext context) => IconsDemo(),
305    ),
306    GalleryDemo(
307      title: 'Lists',
308      subtitle: 'Scrolling list layouts',
309      icon: GalleryIcons.list_alt,
310      category: _kMaterialComponents,
311      routeName: ListDemo.routeName,
312      documentationUrl: 'https://docs.flutter.io/flutter/material/ListTile-class.html',
313      buildRoute: (BuildContext context) => const ListDemo(),
314    ),
315    GalleryDemo(
316      title: 'Lists: leave-behind list items',
317      subtitle: 'List items with hidden actions',
318      icon: GalleryIcons.lists_leave_behind,
319      category: _kMaterialComponents,
320      routeName: LeaveBehindDemo.routeName,
321      documentationUrl: 'https://docs.flutter.io/flutter/widgets/Dismissible-class.html',
322      buildRoute: (BuildContext context) => const LeaveBehindDemo(),
323    ),
324    GalleryDemo(
325      title: 'Lists: reorderable',
326      subtitle: 'Reorderable lists',
327      icon: GalleryIcons.list_alt,
328      category: _kMaterialComponents,
329      routeName: ReorderableListDemo.routeName,
330      documentationUrl: 'https://docs.flutter.io/flutter/material/ReorderableListView-class.html',
331      buildRoute: (BuildContext context) => const ReorderableListDemo(),
332    ),
333    GalleryDemo(
334      title: 'Menus',
335      subtitle: 'Menu buttons and simple menus',
336      icon: GalleryIcons.more_vert,
337      category: _kMaterialComponents,
338      routeName: MenuDemo.routeName,
339      documentationUrl: 'https://docs.flutter.io/flutter/material/PopupMenuButton-class.html',
340      buildRoute: (BuildContext context) => const MenuDemo(),
341    ),
342    GalleryDemo(
343      title: 'Navigation drawer',
344      subtitle: 'Navigation drawer with standard header',
345      icon: GalleryIcons.menu,
346      category: _kMaterialComponents,
347      routeName: DrawerDemo.routeName,
348      documentationUrl: 'https://docs.flutter.io/flutter/material/Drawer-class.html',
349      buildRoute: (BuildContext context) => DrawerDemo(),
350    ),
351    GalleryDemo(
352      title: 'Pagination',
353      subtitle: 'PageView with indicator',
354      icon: GalleryIcons.page_control,
355      category: _kMaterialComponents,
356      routeName: PageSelectorDemo.routeName,
357      documentationUrl: 'https://docs.flutter.io/flutter/material/TabBarView-class.html',
358      buildRoute: (BuildContext context) => PageSelectorDemo(),
359    ),
360    GalleryDemo(
361      title: 'Pickers',
362      subtitle: 'Date and time selection widgets',
363      icon: GalleryIcons.event,
364      category: _kMaterialComponents,
365      routeName: DateAndTimePickerDemo.routeName,
366      documentationUrl: 'https://docs.flutter.io/flutter/material/showDatePicker.html',
367      buildRoute: (BuildContext context) => DateAndTimePickerDemo(),
368    ),
369    GalleryDemo(
370      title: 'Progress indicators',
371      subtitle: 'Linear, circular, indeterminate',
372      icon: GalleryIcons.progress_activity,
373      category: _kMaterialComponents,
374      routeName: ProgressIndicatorDemo.routeName,
375      documentationUrl: 'https://docs.flutter.io/flutter/material/LinearProgressIndicator-class.html',
376      buildRoute: (BuildContext context) => ProgressIndicatorDemo(),
377    ),
378    GalleryDemo(
379      title: 'Pull to refresh',
380      subtitle: 'Refresh indicators',
381      icon: GalleryIcons.refresh,
382      category: _kMaterialComponents,
383      routeName: OverscrollDemo.routeName,
384      documentationUrl: 'https://docs.flutter.io/flutter/material/RefreshIndicator-class.html',
385      buildRoute: (BuildContext context) => const OverscrollDemo(),
386    ),
387    GalleryDemo(
388      title: 'Search',
389      subtitle: 'Expandable search',
390      icon: Icons.search,
391      category: _kMaterialComponents,
392      routeName: SearchDemo.routeName,
393      documentationUrl: 'https://docs.flutter.io/flutter/material/showSearch.html',
394      buildRoute: (BuildContext context) => SearchDemo(),
395    ),
396    GalleryDemo(
397      title: 'Selection controls',
398      subtitle: 'Checkboxes, radio buttons, and switches',
399      icon: GalleryIcons.check_box,
400      category: _kMaterialComponents,
401      routeName: SelectionControlsDemo.routeName,
402      buildRoute: (BuildContext context) => SelectionControlsDemo(),
403    ),
404    GalleryDemo(
405      title: 'Sliders',
406      subtitle: 'Widgets for selecting a value by swiping',
407      icon: GalleryIcons.sliders,
408      category: _kMaterialComponents,
409      routeName: SliderDemo.routeName,
410      documentationUrl: 'https://docs.flutter.io/flutter/material/Slider-class.html',
411      buildRoute: (BuildContext context) => SliderDemo(),
412    ),
413    GalleryDemo(
414      title: 'Snackbar',
415      subtitle: 'Temporary messaging',
416      icon: GalleryIcons.snackbar,
417      category: _kMaterialComponents,
418      routeName: SnackBarDemo.routeName,
419      documentationUrl: 'https://docs.flutter.io/flutter/material/ScaffoldState/showSnackBar.html',
420      buildRoute: (BuildContext context) => const SnackBarDemo(),
421    ),
422    GalleryDemo(
423      title: 'Tabs',
424      subtitle: 'Tabs with independently scrollable views',
425      icon: GalleryIcons.tabs,
426      category: _kMaterialComponents,
427      routeName: TabsDemo.routeName,
428      documentationUrl: 'https://docs.flutter.io/flutter/material/TabBarView-class.html',
429      buildRoute: (BuildContext context) => TabsDemo(),
430    ),
431    GalleryDemo(
432      title: 'Tabs: Scrolling',
433      subtitle: 'Tab bar that scrolls',
434      category: _kMaterialComponents,
435      icon: GalleryIcons.tabs,
436      routeName: ScrollableTabsDemo.routeName,
437      documentationUrl: 'https://docs.flutter.io/flutter/material/TabBar-class.html',
438      buildRoute: (BuildContext context) => ScrollableTabsDemo(),
439    ),
440    GalleryDemo(
441      title: 'Text fields',
442      subtitle: 'Single line of editable text and numbers',
443      icon: GalleryIcons.text_fields_alt,
444      category: _kMaterialComponents,
445      routeName: TextFormFieldDemo.routeName,
446      documentationUrl: 'https://docs.flutter.io/flutter/material/TextFormField-class.html',
447      buildRoute: (BuildContext context) => const TextFormFieldDemo(),
448    ),
449    GalleryDemo(
450      title: 'Tooltips',
451      subtitle: 'Short message displayed on long-press',
452      icon: GalleryIcons.tooltip,
453      category: _kMaterialComponents,
454      routeName: TooltipDemo.routeName,
455      documentationUrl: 'https://docs.flutter.io/flutter/material/Tooltip-class.html',
456      buildRoute: (BuildContext context) => TooltipDemo(),
457    ),
458
459    // Cupertino Components
460    GalleryDemo(
461      title: 'Activity Indicator',
462      icon: GalleryIcons.cupertino_progress,
463      category: _kCupertinoComponents,
464      routeName: CupertinoProgressIndicatorDemo.routeName,
465      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoActivityIndicator-class.html',
466      buildRoute: (BuildContext context) => CupertinoProgressIndicatorDemo(),
467    ),
468    GalleryDemo(
469      title: 'Alerts',
470      icon: GalleryIcons.dialogs,
471      category: _kCupertinoComponents,
472      routeName: CupertinoAlertDemo.routeName,
473      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/showCupertinoDialog.html',
474      buildRoute: (BuildContext context) => CupertinoAlertDemo(),
475    ),
476    GalleryDemo(
477      title: 'Buttons',
478      icon: GalleryIcons.generic_buttons,
479      category: _kCupertinoComponents,
480      routeName: CupertinoButtonsDemo.routeName,
481      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoButton-class.html',
482      buildRoute: (BuildContext context) => CupertinoButtonsDemo(),
483    ),
484    GalleryDemo(
485      title: 'Navigation',
486      icon: GalleryIcons.bottom_navigation,
487      category: _kCupertinoComponents,
488      routeName: CupertinoNavigationDemo.routeName,
489      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoTabScaffold-class.html',
490      buildRoute: (BuildContext context) => CupertinoNavigationDemo(),
491    ),
492    GalleryDemo(
493      title: 'Pickers',
494      icon: GalleryIcons.event,
495      category: _kCupertinoComponents,
496      routeName: CupertinoPickerDemo.routeName,
497      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoPicker-class.html',
498      buildRoute: (BuildContext context) => CupertinoPickerDemo(),
499    ),
500    GalleryDemo(
501      title: 'Pull to refresh',
502      icon: GalleryIcons.cupertino_pull_to_refresh,
503      category: _kCupertinoComponents,
504      routeName: CupertinoRefreshControlDemo.routeName,
505      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSliverRefreshControl-class.html',
506      buildRoute: (BuildContext context) => CupertinoRefreshControlDemo(),
507    ),
508    GalleryDemo(
509      title: 'Segmented Control',
510      icon: GalleryIcons.tabs,
511      category: _kCupertinoComponents,
512      routeName: CupertinoSegmentedControlDemo.routeName,
513      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSegmentedControl-class.html',
514      buildRoute: (BuildContext context) => CupertinoSegmentedControlDemo(),
515    ),
516    GalleryDemo(
517      title: 'Sliders',
518      icon: GalleryIcons.sliders,
519      category: _kCupertinoComponents,
520      routeName: CupertinoSliderDemo.routeName,
521      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSlider-class.html',
522      buildRoute: (BuildContext context) => CupertinoSliderDemo(),
523    ),
524    GalleryDemo(
525      title: 'Switches',
526      icon: GalleryIcons.cupertino_switch,
527      category: _kCupertinoComponents,
528      routeName: CupertinoSwitchDemo.routeName,
529      documentationUrl: 'https://docs.flutter.io/flutter/cupertino/CupertinoSwitch-class.html',
530      buildRoute: (BuildContext context) => CupertinoSwitchDemo(),
531    ),
532    GalleryDemo(
533      title: 'Text Fields',
534      icon: GalleryIcons.text_fields_alt,
535      category: _kCupertinoComponents,
536      routeName: CupertinoTextFieldDemo.routeName,
537      buildRoute: (BuildContext context) => CupertinoTextFieldDemo(),
538    ),
539
540    // Media
541    GalleryDemo(
542      title: 'Animated images',
543      subtitle: 'GIF and WebP animations',
544      icon: GalleryIcons.animation,
545      category: _kMedia,
546      routeName: ImagesDemo.routeName,
547      buildRoute: (BuildContext context) => ImagesDemo(),
548    ),
549    GalleryDemo(
550      title: 'Video',
551      subtitle: 'Video playback',
552      icon: GalleryIcons.drive_video,
553      category: _kMedia,
554      routeName: VideoDemo.routeName,
555      buildRoute: (BuildContext context) => const VideoDemo(),
556    ),
557  ];
558
559  // Keep Pesto around for its regression test value. It is not included
560  // in (release builds) the performance tests.
561  assert(() {
562    galleryDemos.insert(0,
563      GalleryDemo(
564        title: 'Pesto',
565        subtitle: 'Simple recipe browser',
566        icon: Icons.adjust,
567        category: _kDemos,
568        routeName: PestoDemo.routeName,
569        buildRoute: (BuildContext context) => const PestoDemo(),
570      ),
571    );
572    return true;
573  }());
574
575  return galleryDemos;
576}
577
578final List<GalleryDemo> kAllGalleryDemos = _buildGalleryDemos();
579
580final Set<GalleryDemoCategory> kAllGalleryDemoCategories =
581  kAllGalleryDemos.map<GalleryDemoCategory>((GalleryDemo demo) => demo.category).toSet();
582
583final Map<GalleryDemoCategory, List<GalleryDemo>> kGalleryCategoryToDemos =
584  Map<GalleryDemoCategory, List<GalleryDemo>>.fromIterable(
585    kAllGalleryDemoCategories,
586    value: (dynamic category) {
587      return kAllGalleryDemos.where((GalleryDemo demo) => demo.category == category).toList();
588    },
589  );
590
591final Map<String, String> kDemoDocumentationUrl =
592    Map<String, String>.fromIterable(
593      kAllGalleryDemos.where((GalleryDemo demo) => demo.documentationUrl != null),
594      key: (dynamic demo) => demo.routeName,
595      value: (dynamic demo) => demo.documentationUrl,
596    );
597