From 74c3e74fbadc7f327fe24a876fd10edbe296d923 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Mon, 9 May 2016 11:00:54 -0700 Subject: [PATCH] Call it Flutter Gallery (#3801) --- dev/tools/mega_gallery.dart | 10 +- examples/README.md | 2 +- .../.gitignore | 0 .../README.md | 4 +- .../android/AndroidManifest.xml | 19 + .../android/res/mipmap-hdpi/ic_launcher.png | Bin .../android/res/mipmap-mdpi/ic_launcher.png | Bin .../android/res/mipmap-xhdpi/ic_launcher.png | Bin .../android/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher.png | Bin .../assets/flutter_logo.png | Bin .../assets/section_animation.png | Bin .../assets/section_components.png | Bin .../assets/section_layout.png | Bin .../assets/section_patterns.png | Bin .../assets/section_style.png | Bin .../assets/section_usability.png | Bin .../flutter.yaml | 2 +- .../ios/.gitignore | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-60@2x.png | Bin .../AppIcon.appiconset/Icon-60@3x.png | Bin .../AppIcon.appiconset/Icon-76.png | Bin .../AppIcon.appiconset/Icon-76@2x.png | Bin .../AppIcon.appiconset/Icon-83.5@2x.png | Bin .../AppIcon.appiconset/Icon-Small-40.png | Bin .../AppIcon.appiconset/Icon-Small-40@2x.png | Bin .../AppIcon.appiconset/Icon-Small-40@3x.png | Bin .../AppIcon.appiconset/Icon-Small.png | Bin .../AppIcon.appiconset/Icon-Small@2x.png | Bin .../AppIcon.appiconset/Icon-Small@3x.png | Bin .../AppIcon.appiconset/icon_128x128.png | Bin .../AppIcon.appiconset/icon_128x128@2x.png | Bin .../AppIcon.appiconset/icon_16x16.png | Bin .../AppIcon.appiconset/icon_16x16@2x.png | Bin .../AppIcon.appiconset/icon_256x256.png | Bin .../AppIcon.appiconset/icon_256x256@2x.png | Bin .../AppIcon.appiconset/icon_32x32.png | Bin .../AppIcon.appiconset/icon_32x32@2x.png | Bin .../AppIcon.appiconset/icon_512x512.png | Bin .../AppIcon.appiconset/icon_512x512@2x.png | Bin .../ios/Info.plist | 2 +- .../ios/LaunchScreen.storyboard | 0 .../lib/demo/all.dart | 0 .../lib/demo/buttons_demo.dart | 0 .../lib/demo/cards_demo.dart | 0 .../lib/demo/chip_demo.dart | 0 .../lib/demo/colors_demo.dart | 0 .../lib/demo/data_table_demo.dart | 0 .../lib/demo/date_picker_demo.dart | 0 .../lib/demo/dialog_demo.dart | 0 .../lib/demo/drawing_demo.dart | 0 .../lib/demo/drop_down_demo.dart | 0 examples/flutter_gallery/lib/demo/fail.dart | 24 + .../lib/demo/fitness_demo.dart | 0 .../lib/demo/flexible_space_demo.dart | 0 .../lib/demo/full_screen_dialog_demo.dart | 0 .../lib/demo/grid_list_demo.dart | 0 .../lib/demo/icons_demo.dart | 0 .../lib/demo/leave_behind_demo.dart | 0 .../lib/demo/list_demo.dart | 0 .../lib/demo/menu_demo.dart | 0 .../lib/demo/modal_bottom_sheet_demo.dart | 0 .../lib/demo/overscroll_demo.dart | 0 .../lib/demo/page_selector_demo.dart | 0 .../demo/persistent_bottom_sheet_demo.dart | 0 .../lib/demo/progress_indicator_demo.dart | 0 .../lib/demo/scrollable_tabs_demo.dart | 0 .../lib/demo/scrolling_techniques_demo.dart | 0 .../lib/demo/selection_controls_demo.dart | 2 +- .../lib/demo/slider_demo.dart | 0 .../lib/demo/snack_bar_demo.dart | 0 .../lib/demo/tabs_demo.dart | 0 .../lib/demo/tabs_fab_demo.dart | 0 .../lib/demo/text_field_demo.dart | 0 .../lib/demo/time_picker_demo.dart | 0 .../lib/demo/tooltip_demo.dart | 4 +- .../lib/demo/two_level_list_demo.dart | 0 .../lib/demo/typography_demo.dart | 0 .../lib/demo/weather_demo.dart | 0 .../lib/gallery/app.dart | 2 +- .../lib/gallery/demo.dart | 2 +- .../lib/gallery/drawer.dart | 2 +- .../lib/gallery/example_code.dart | 0 .../lib/gallery/example_code_parser.dart | 0 .../lib/gallery/header.dart | 0 .../lib/gallery/home.dart | 0 .../lib/gallery/item.dart | 0 .../lib/gallery/syntax_highlighter.dart | 0 .../lib/main.dart | 0 .../material_gallery/.gitignore | 9 + .../material_gallery/README.md | 12 + .../android/AndroidManifest.xml | 2 +- .../android/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2453 bytes .../android/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1572 bytes .../android/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3602 bytes .../android/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5800 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 8870 bytes .../material_gallery/assets/flutter_logo.png | Bin 0 -> 5666 bytes .../assets/section_animation.png | Bin 0 -> 4221 bytes .../assets/section_components.png | Bin 0 -> 5665 bytes .../assets/section_layout.png | Bin 0 -> 3765 bytes .../assets/section_patterns.png | Bin 0 -> 2291 bytes .../material_gallery/assets/section_style.png | Bin 0 -> 5562 bytes .../assets/section_usability.png | Bin 0 -> 10615 bytes .../material_gallery/flutter.yaml | 41 ++ .../material_gallery/ios/.gitignore | 1 + .../AppIcon.appiconset/Contents.json | 142 +++++ .../AppIcon.appiconset/Icon-60@2x.png | Bin 0 -> 4630 bytes .../AppIcon.appiconset/Icon-60@3x.png | Bin 0 -> 7707 bytes .../AppIcon.appiconset/Icon-76.png | Bin 0 -> 2763 bytes .../AppIcon.appiconset/Icon-76@2x.png | Bin 0 -> 6241 bytes .../AppIcon.appiconset/Icon-83.5@2x.png | Bin 0 -> 6981 bytes .../AppIcon.appiconset/Icon-Small-40.png | Bin 0 -> 1293 bytes .../AppIcon.appiconset/Icon-Small-40@2x.png | Bin 0 -> 2952 bytes .../AppIcon.appiconset/Icon-Small-40@3x.png | Bin 0 -> 4630 bytes .../AppIcon.appiconset/Icon-Small.png | Bin 0 -> 869 bytes .../AppIcon.appiconset/Icon-Small@2x.png | Bin 0 -> 1976 bytes .../AppIcon.appiconset/Icon-Small@3x.png | Bin 0 -> 3216 bytes .../AppIcon.appiconset/icon_128x128.png | Bin 0 -> 5057 bytes .../AppIcon.appiconset/icon_128x128@2x.png | Bin 0 -> 11759 bytes .../AppIcon.appiconset/icon_16x16.png | Bin 0 -> 425 bytes .../AppIcon.appiconset/icon_16x16@2x.png | Bin 0 -> 952 bytes .../AppIcon.appiconset/icon_256x256.png | Bin 0 -> 11759 bytes .../AppIcon.appiconset/icon_256x256@2x.png | Bin 0 -> 29082 bytes .../AppIcon.appiconset/icon_32x32.png | Bin 0 -> 952 bytes .../AppIcon.appiconset/icon_32x32@2x.png | Bin 0 -> 2237 bytes .../AppIcon.appiconset/icon_512x512.png | Bin 0 -> 29082 bytes .../AppIcon.appiconset/icon_512x512@2x.png | Bin 0 -> 57476 bytes .../material_gallery/ios/Info.plist | 47 ++ .../ios/LaunchScreen.storyboard | 27 + .../material_gallery/lib/demo/all.dart | 37 ++ .../lib/demo/buttons_demo.dart | 196 ++++++ .../material_gallery/lib/demo/cards_demo.dart | 143 +++++ .../material_gallery/lib/demo/chip_demo.dart | 54 ++ .../lib/demo/colors_demo.dart | 138 ++++ .../lib/demo/data_table_demo.dart | 147 +++++ .../lib/demo/date_picker_demo.dart | 52 ++ .../lib/demo/dialog_demo.dart | 203 ++++++ .../lib/demo/drawing_demo.dart | 85 +++ .../lib/demo/drop_down_demo.dart | 42 ++ .../lib/demo/fitness_demo.dart | 589 ++++++++++++++++++ .../lib/demo/flexible_space_demo.dart | 204 ++++++ .../lib/demo/full_screen_dialog_demo.dart | 246 ++++++++ .../lib/demo/grid_list_demo.dart | 283 +++++++++ .../material_gallery/lib/demo/icons_demo.dart | 162 +++++ .../lib/demo/leave_behind_demo.dart | 170 +++++ .../material_gallery/lib/demo/list_demo.dart | 205 ++++++ .../material_gallery/lib/demo/menu_demo.dart | 216 +++++++ .../lib/demo/modal_bottom_sheet_demo.dart | 39 ++ .../lib/demo/overscroll_demo.dart | 95 +++ .../lib/demo/page_selector_demo.dart | 81 +++ .../demo/persistent_bottom_sheet_demo.dart | 73 +++ .../lib/demo/progress_indicator_demo.dart | 113 ++++ .../lib/demo/scrollable_tabs_demo.dart | 111 ++++ .../lib/demo/scrolling_techniques_demo.dart | 159 +++++ .../lib/demo/selection_controls_demo.dart | 180 ++++++ .../lib/demo/slider_demo.dart | 56 ++ .../lib/demo/snack_bar_demo.dart | 84 +++ .../material_gallery/lib/demo/tabs_demo.dart | 82 +++ .../lib/demo/tabs_fab_demo.dart | 118 ++++ .../lib/demo/text_field_demo.dart | 120 ++++ .../lib/demo/time_picker_demo.dart | 48 ++ .../lib/demo/tooltip_demo.dart | 68 ++ .../lib/demo/two_level_list_demo.dart | 32 + .../lib/demo/typography_demo.dart | 73 +++ .../lib/demo/weather_demo.dart | 559 +++++++++++++++++ .../material_gallery/lib/gallery/app.dart | 85 +++ .../material_gallery/lib/gallery/demo.dart | 278 +++++++++ .../material_gallery/lib/gallery/drawer.dart | 99 +++ .../lib/gallery/example_code.dart | 230 +++++++ .../lib/gallery/example_code_parser.dart | 52 ++ .../material_gallery/lib/gallery/header.dart | 198 ++++++ .../material_gallery/lib/gallery/home.dart | 127 ++++ .../material_gallery/lib/gallery/item.dart | 36 ++ .../lib/gallery/syntax_highlighter.dart | 345 ++++++++++ .../material_gallery/lib/main.dart | 11 + .../material_gallery/pubspec.yaml | 2 +- .../test/example_code_parser_test.dart | 4 +- .../material_gallery/test/smoke_test.dart | 14 +- .../test_driver/scroll_perf.dart | 2 +- .../test_driver/scroll_perf_test.dart | 0 .../test_driver/transitions_perf.dart | 2 +- .../test_driver/transitions_perf_test.dart | 0 examples/flutter_gallery/pubspec.yaml | 20 + .../test/example_code_parser_test.dart | 53 ++ examples/flutter_gallery/test/smoke_test.dart | 98 +++ .../test_driver/scroll_perf.dart | 11 + .../test_driver/scroll_perf_test.dart | 53 ++ .../test_driver/transitions_perf.dart | 11 + .../test_driver/transitions_perf_test.dart | 93 +++ .../lib/src/commands/upgrade.dart | 2 +- packages/flutter_tools/lib/src/flx.dart | 2 +- packages/flutter_tools/test/upgrade_test.dart | 5 +- travis/test.sh | 2 +- 195 files changed, 7420 insertions(+), 34 deletions(-) rename examples/{material_gallery => flutter_gallery}/.gitignore (100%) rename examples/{material_gallery => flutter_gallery}/README.md (80%) create mode 100644 examples/flutter_gallery/android/AndroidManifest.xml rename examples/{material_gallery => flutter_gallery}/android/res/mipmap-hdpi/ic_launcher.png (100%) rename examples/{material_gallery => flutter_gallery}/android/res/mipmap-mdpi/ic_launcher.png (100%) rename examples/{material_gallery => flutter_gallery}/android/res/mipmap-xhdpi/ic_launcher.png (100%) rename examples/{material_gallery => flutter_gallery}/android/res/mipmap-xxhdpi/ic_launcher.png (100%) rename examples/{material_gallery => flutter_gallery}/android/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/flutter_logo.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_animation.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_components.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_layout.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_patterns.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_style.png (100%) rename examples/{material_gallery => flutter_gallery}/assets/section_usability.png (100%) rename examples/{material_gallery => flutter_gallery}/flutter.yaml (98%) rename examples/{material_gallery => flutter_gallery}/ios/.gitignore (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png (100%) rename examples/{material_gallery => flutter_gallery}/ios/Info.plist (97%) rename examples/{material_gallery => flutter_gallery}/ios/LaunchScreen.storyboard (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/all.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/buttons_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/cards_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/chip_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/colors_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/data_table_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/date_picker_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/dialog_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/drawing_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/drop_down_demo.dart (100%) create mode 100644 examples/flutter_gallery/lib/demo/fail.dart rename examples/{material_gallery => flutter_gallery}/lib/demo/fitness_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/flexible_space_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/full_screen_dialog_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/grid_list_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/icons_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/leave_behind_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/list_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/menu_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/modal_bottom_sheet_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/overscroll_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/page_selector_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/persistent_bottom_sheet_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/progress_indicator_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/scrollable_tabs_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/scrolling_techniques_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/selection_controls_demo.dart (99%) rename examples/{material_gallery => flutter_gallery}/lib/demo/slider_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/snack_bar_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/tabs_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/tabs_fab_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/text_field_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/time_picker_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/tooltip_demo.dart (96%) rename examples/{material_gallery => flutter_gallery}/lib/demo/two_level_list_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/typography_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/demo/weather_demo.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/app.dart (99%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/demo.dart (99%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/drawer.dart (97%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/example_code.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/example_code_parser.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/header.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/home.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/item.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/gallery/syntax_highlighter.dart (100%) rename examples/{material_gallery => flutter_gallery}/lib/main.dart (100%) create mode 100644 examples/flutter_gallery/material_gallery/.gitignore create mode 100644 examples/flutter_gallery/material_gallery/README.md rename examples/{ => flutter_gallery}/material_gallery/android/AndroidManifest.xml (93%) create mode 100644 examples/flutter_gallery/material_gallery/android/res/mipmap-hdpi/ic_launcher.png create mode 100644 examples/flutter_gallery/material_gallery/android/res/mipmap-mdpi/ic_launcher.png create mode 100644 examples/flutter_gallery/material_gallery/android/res/mipmap-xhdpi/ic_launcher.png create mode 100644 examples/flutter_gallery/material_gallery/android/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 examples/flutter_gallery/material_gallery/android/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 examples/flutter_gallery/material_gallery/assets/flutter_logo.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_animation.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_components.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_layout.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_patterns.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_style.png create mode 100644 examples/flutter_gallery/material_gallery/assets/section_usability.png create mode 100644 examples/flutter_gallery/material_gallery/flutter.yaml create mode 100644 examples/flutter_gallery/material_gallery/ios/.gitignore create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png create mode 100644 examples/flutter_gallery/material_gallery/ios/Info.plist create mode 100644 examples/flutter_gallery/material_gallery/ios/LaunchScreen.storyboard create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/all.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/buttons_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/cards_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/chip_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/colors_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/data_table_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/date_picker_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/dialog_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/drawing_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/drop_down_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/fitness_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/flexible_space_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/full_screen_dialog_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/grid_list_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/icons_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/leave_behind_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/list_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/menu_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/modal_bottom_sheet_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/overscroll_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/page_selector_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/progress_indicator_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/scrollable_tabs_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/scrolling_techniques_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/selection_controls_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/slider_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/snack_bar_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/tabs_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/tabs_fab_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/text_field_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/time_picker_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/tooltip_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/two_level_list_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/typography_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/demo/weather_demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/app.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/demo.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/drawer.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/example_code.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/example_code_parser.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/header.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/home.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/item.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/gallery/syntax_highlighter.dart create mode 100644 examples/flutter_gallery/material_gallery/lib/main.dart rename examples/{ => flutter_gallery}/material_gallery/pubspec.yaml (95%) rename examples/{ => flutter_gallery}/material_gallery/test/example_code_parser_test.dart (90%) rename examples/{ => flutter_gallery}/material_gallery/test/smoke_test.dart (86%) rename examples/{ => flutter_gallery}/material_gallery/test_driver/scroll_perf.dart (84%) rename examples/{ => flutter_gallery}/material_gallery/test_driver/scroll_perf_test.dart (100%) rename examples/{ => flutter_gallery}/material_gallery/test_driver/transitions_perf.dart (84%) rename examples/{ => flutter_gallery}/material_gallery/test_driver/transitions_perf_test.dart (100%) create mode 100644 examples/flutter_gallery/pubspec.yaml create mode 100644 examples/flutter_gallery/test/example_code_parser_test.dart create mode 100644 examples/flutter_gallery/test/smoke_test.dart create mode 100644 examples/flutter_gallery/test_driver/scroll_perf.dart create mode 100644 examples/flutter_gallery/test_driver/scroll_perf_test.dart create mode 100644 examples/flutter_gallery/test_driver/transitions_perf.dart create mode 100644 examples/flutter_gallery/test_driver/transitions_perf_test.dart diff --git a/dev/tools/mega_gallery.dart b/dev/tools/mega_gallery.dart index 3540af75e2..bdeb4e010f 100644 --- a/dev/tools/mega_gallery.dart +++ b/dev/tools/mega_gallery.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/// Make `n` copies of material_gallery. +/// Make `n` copies of flutter_gallery. import 'dart:io'; @@ -27,13 +27,13 @@ void main(List args) { ArgResults results = argParser.parse(args); if (results['help']) { - print('Generate n copies of material_gallery.\n'); + print('Generate n copies of flutter_gallery.\n'); print('usage: dart mega_gallery.dart '); print(argParser.usage); exit(0); } - Directory source = new Directory(_normalize('examples/material_gallery')); + Directory source = new Directory(_normalize('examples/flutter_gallery')); Directory out = new Directory(_normalize(results['out'])); if (results['delete']) { @@ -55,10 +55,10 @@ void main(List args) { print('Stats:'); print(' packages/flutter : ${getStatsFor(new Directory("packages/flutter"))}'); - print(' examples/material_gallery : ${getStatsFor(new Directory("examples/material_gallery"))}'); + print(' examples/flutter_gallery : ${getStatsFor(new Directory("examples/flutter_gallery"))}'); print(''); - print('Making $copies copies of material_gallery:'); + print('Making $copies copies of flutter_gallery:'); Directory lib = _dir(out, 'lib'); if (lib.existsSync()) diff --git a/examples/README.md b/examples/README.md index 4cbd73a110..3182f7484e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,7 +13,7 @@ Available examples include: - **Hello, world** The [hello world app](hello_world) is a basic app that shows the text "hello, world." -- **Material Gallery** The [material gallery app](material_gallery) showcases +- **Flutter gallery** The [flutter gallery app](flutter_gallery) showcases Flutter's implementation of [material design](https://www.google.com/design/spec/material-design/introduction.html). - **Layers** The [layers vignettes](layers) show how to use the various layers diff --git a/examples/material_gallery/.gitignore b/examples/flutter_gallery/.gitignore similarity index 100% rename from examples/material_gallery/.gitignore rename to examples/flutter_gallery/.gitignore diff --git a/examples/material_gallery/README.md b/examples/flutter_gallery/README.md similarity index 80% rename from examples/material_gallery/README.md rename to examples/flutter_gallery/README.md index bb62601cd2..0d13d4db89 100644 --- a/examples/material_gallery/README.md +++ b/examples/flutter_gallery/README.md @@ -1,6 +1,6 @@ -# Flutter Material Gallery +# Flutter gallery -Demo app for the Material Design widgets implemented in Flutter. +Demo app for the Material Design widgets and other features provided by Flutter. ## Icon diff --git a/examples/flutter_gallery/android/AndroidManifest.xml b/examples/flutter_gallery/android/AndroidManifest.xml new file mode 100644 index 0000000000..2024e84000 --- /dev/null +++ b/examples/flutter_gallery/android/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/examples/material_gallery/android/res/mipmap-hdpi/ic_launcher.png b/examples/flutter_gallery/android/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from examples/material_gallery/android/res/mipmap-hdpi/ic_launcher.png rename to examples/flutter_gallery/android/res/mipmap-hdpi/ic_launcher.png diff --git a/examples/material_gallery/android/res/mipmap-mdpi/ic_launcher.png b/examples/flutter_gallery/android/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from examples/material_gallery/android/res/mipmap-mdpi/ic_launcher.png rename to examples/flutter_gallery/android/res/mipmap-mdpi/ic_launcher.png diff --git a/examples/material_gallery/android/res/mipmap-xhdpi/ic_launcher.png b/examples/flutter_gallery/android/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from examples/material_gallery/android/res/mipmap-xhdpi/ic_launcher.png rename to examples/flutter_gallery/android/res/mipmap-xhdpi/ic_launcher.png diff --git a/examples/material_gallery/android/res/mipmap-xxhdpi/ic_launcher.png b/examples/flutter_gallery/android/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from examples/material_gallery/android/res/mipmap-xxhdpi/ic_launcher.png rename to examples/flutter_gallery/android/res/mipmap-xxhdpi/ic_launcher.png diff --git a/examples/material_gallery/android/res/mipmap-xxxhdpi/ic_launcher.png b/examples/flutter_gallery/android/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from examples/material_gallery/android/res/mipmap-xxxhdpi/ic_launcher.png rename to examples/flutter_gallery/android/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/examples/material_gallery/assets/flutter_logo.png b/examples/flutter_gallery/assets/flutter_logo.png similarity index 100% rename from examples/material_gallery/assets/flutter_logo.png rename to examples/flutter_gallery/assets/flutter_logo.png diff --git a/examples/material_gallery/assets/section_animation.png b/examples/flutter_gallery/assets/section_animation.png similarity index 100% rename from examples/material_gallery/assets/section_animation.png rename to examples/flutter_gallery/assets/section_animation.png diff --git a/examples/material_gallery/assets/section_components.png b/examples/flutter_gallery/assets/section_components.png similarity index 100% rename from examples/material_gallery/assets/section_components.png rename to examples/flutter_gallery/assets/section_components.png diff --git a/examples/material_gallery/assets/section_layout.png b/examples/flutter_gallery/assets/section_layout.png similarity index 100% rename from examples/material_gallery/assets/section_layout.png rename to examples/flutter_gallery/assets/section_layout.png diff --git a/examples/material_gallery/assets/section_patterns.png b/examples/flutter_gallery/assets/section_patterns.png similarity index 100% rename from examples/material_gallery/assets/section_patterns.png rename to examples/flutter_gallery/assets/section_patterns.png diff --git a/examples/material_gallery/assets/section_style.png b/examples/flutter_gallery/assets/section_style.png similarity index 100% rename from examples/material_gallery/assets/section_style.png rename to examples/flutter_gallery/assets/section_style.png diff --git a/examples/material_gallery/assets/section_usability.png b/examples/flutter_gallery/assets/section_usability.png similarity index 100% rename from examples/material_gallery/assets/section_usability.png rename to examples/flutter_gallery/assets/section_usability.png diff --git a/examples/material_gallery/flutter.yaml b/examples/flutter_gallery/flutter.yaml similarity index 98% rename from examples/material_gallery/flutter.yaml rename to examples/flutter_gallery/flutter.yaml index 9639d3b59b..7a2ca11994 100644 --- a/examples/material_gallery/flutter.yaml +++ b/examples/flutter_gallery/flutter.yaml @@ -1,4 +1,4 @@ -name: material_gallery +name: flutter_gallery uses-material-design: true assets: - assets/flutter_logo.png diff --git a/examples/material_gallery/ios/.gitignore b/examples/flutter_gallery/ios/.gitignore similarity index 100% rename from examples/material_gallery/ios/.gitignore rename to examples/flutter_gallery/ios/.gitignore diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Contents.json rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png diff --git a/examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png similarity index 100% rename from examples/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png rename to examples/flutter_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png diff --git a/examples/material_gallery/ios/Info.plist b/examples/flutter_gallery/ios/Info.plist similarity index 97% rename from examples/material_gallery/ios/Info.plist rename to examples/flutter_gallery/ios/Info.plist index 69341571d3..c89ab01a94 100644 --- a/examples/material_gallery/ios/Info.plist +++ b/examples/flutter_gallery/ios/Info.plist @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - Material Gallery + Flutter gallery CFBundlePackageType APPL CFBundleShortVersionString diff --git a/examples/material_gallery/ios/LaunchScreen.storyboard b/examples/flutter_gallery/ios/LaunchScreen.storyboard similarity index 100% rename from examples/material_gallery/ios/LaunchScreen.storyboard rename to examples/flutter_gallery/ios/LaunchScreen.storyboard diff --git a/examples/material_gallery/lib/demo/all.dart b/examples/flutter_gallery/lib/demo/all.dart similarity index 100% rename from examples/material_gallery/lib/demo/all.dart rename to examples/flutter_gallery/lib/demo/all.dart diff --git a/examples/material_gallery/lib/demo/buttons_demo.dart b/examples/flutter_gallery/lib/demo/buttons_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/buttons_demo.dart rename to examples/flutter_gallery/lib/demo/buttons_demo.dart diff --git a/examples/material_gallery/lib/demo/cards_demo.dart b/examples/flutter_gallery/lib/demo/cards_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/cards_demo.dart rename to examples/flutter_gallery/lib/demo/cards_demo.dart diff --git a/examples/material_gallery/lib/demo/chip_demo.dart b/examples/flutter_gallery/lib/demo/chip_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/chip_demo.dart rename to examples/flutter_gallery/lib/demo/chip_demo.dart diff --git a/examples/material_gallery/lib/demo/colors_demo.dart b/examples/flutter_gallery/lib/demo/colors_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/colors_demo.dart rename to examples/flutter_gallery/lib/demo/colors_demo.dart diff --git a/examples/material_gallery/lib/demo/data_table_demo.dart b/examples/flutter_gallery/lib/demo/data_table_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/data_table_demo.dart rename to examples/flutter_gallery/lib/demo/data_table_demo.dart diff --git a/examples/material_gallery/lib/demo/date_picker_demo.dart b/examples/flutter_gallery/lib/demo/date_picker_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/date_picker_demo.dart rename to examples/flutter_gallery/lib/demo/date_picker_demo.dart diff --git a/examples/material_gallery/lib/demo/dialog_demo.dart b/examples/flutter_gallery/lib/demo/dialog_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/dialog_demo.dart rename to examples/flutter_gallery/lib/demo/dialog_demo.dart diff --git a/examples/material_gallery/lib/demo/drawing_demo.dart b/examples/flutter_gallery/lib/demo/drawing_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/drawing_demo.dart rename to examples/flutter_gallery/lib/demo/drawing_demo.dart diff --git a/examples/material_gallery/lib/demo/drop_down_demo.dart b/examples/flutter_gallery/lib/demo/drop_down_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/drop_down_demo.dart rename to examples/flutter_gallery/lib/demo/drop_down_demo.dart diff --git a/examples/flutter_gallery/lib/demo/fail.dart b/examples/flutter_gallery/lib/demo/fail.dart new file mode 100644 index 0000000000..049a1b161b --- /dev/null +++ b/examples/flutter_gallery/lib/demo/fail.dart @@ -0,0 +1,24 @@ + +import 'package:flutter/material.dart'; + +class LimitDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('LimitedBox test') + ), + body: new Block( + children: [ + new LimitedBox( + maxWidth: 100.0, + maxHeight: 100.0, + child: new Container( + decoration: new BoxDecoration(backgroundColor: const Color(0xFF00FF00)) + ) + ) + ] + ) + ); + } +} diff --git a/examples/material_gallery/lib/demo/fitness_demo.dart b/examples/flutter_gallery/lib/demo/fitness_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/fitness_demo.dart rename to examples/flutter_gallery/lib/demo/fitness_demo.dart diff --git a/examples/material_gallery/lib/demo/flexible_space_demo.dart b/examples/flutter_gallery/lib/demo/flexible_space_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/flexible_space_demo.dart rename to examples/flutter_gallery/lib/demo/flexible_space_demo.dart diff --git a/examples/material_gallery/lib/demo/full_screen_dialog_demo.dart b/examples/flutter_gallery/lib/demo/full_screen_dialog_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/full_screen_dialog_demo.dart rename to examples/flutter_gallery/lib/demo/full_screen_dialog_demo.dart diff --git a/examples/material_gallery/lib/demo/grid_list_demo.dart b/examples/flutter_gallery/lib/demo/grid_list_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/grid_list_demo.dart rename to examples/flutter_gallery/lib/demo/grid_list_demo.dart diff --git a/examples/material_gallery/lib/demo/icons_demo.dart b/examples/flutter_gallery/lib/demo/icons_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/icons_demo.dart rename to examples/flutter_gallery/lib/demo/icons_demo.dart diff --git a/examples/material_gallery/lib/demo/leave_behind_demo.dart b/examples/flutter_gallery/lib/demo/leave_behind_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/leave_behind_demo.dart rename to examples/flutter_gallery/lib/demo/leave_behind_demo.dart diff --git a/examples/material_gallery/lib/demo/list_demo.dart b/examples/flutter_gallery/lib/demo/list_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/list_demo.dart rename to examples/flutter_gallery/lib/demo/list_demo.dart diff --git a/examples/material_gallery/lib/demo/menu_demo.dart b/examples/flutter_gallery/lib/demo/menu_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/menu_demo.dart rename to examples/flutter_gallery/lib/demo/menu_demo.dart diff --git a/examples/material_gallery/lib/demo/modal_bottom_sheet_demo.dart b/examples/flutter_gallery/lib/demo/modal_bottom_sheet_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/modal_bottom_sheet_demo.dart rename to examples/flutter_gallery/lib/demo/modal_bottom_sheet_demo.dart diff --git a/examples/material_gallery/lib/demo/overscroll_demo.dart b/examples/flutter_gallery/lib/demo/overscroll_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/overscroll_demo.dart rename to examples/flutter_gallery/lib/demo/overscroll_demo.dart diff --git a/examples/material_gallery/lib/demo/page_selector_demo.dart b/examples/flutter_gallery/lib/demo/page_selector_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/page_selector_demo.dart rename to examples/flutter_gallery/lib/demo/page_selector_demo.dart diff --git a/examples/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart b/examples/flutter_gallery/lib/demo/persistent_bottom_sheet_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart rename to examples/flutter_gallery/lib/demo/persistent_bottom_sheet_demo.dart diff --git a/examples/material_gallery/lib/demo/progress_indicator_demo.dart b/examples/flutter_gallery/lib/demo/progress_indicator_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/progress_indicator_demo.dart rename to examples/flutter_gallery/lib/demo/progress_indicator_demo.dart diff --git a/examples/material_gallery/lib/demo/scrollable_tabs_demo.dart b/examples/flutter_gallery/lib/demo/scrollable_tabs_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/scrollable_tabs_demo.dart rename to examples/flutter_gallery/lib/demo/scrollable_tabs_demo.dart diff --git a/examples/material_gallery/lib/demo/scrolling_techniques_demo.dart b/examples/flutter_gallery/lib/demo/scrolling_techniques_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/scrolling_techniques_demo.dart rename to examples/flutter_gallery/lib/demo/scrolling_techniques_demo.dart diff --git a/examples/material_gallery/lib/demo/selection_controls_demo.dart b/examples/flutter_gallery/lib/demo/selection_controls_demo.dart similarity index 99% rename from examples/material_gallery/lib/demo/selection_controls_demo.dart rename to examples/flutter_gallery/lib/demo/selection_controls_demo.dart index 69936fd0a0..29213d7f2b 100644 --- a/examples/material_gallery/lib/demo/selection_controls_demo.dart +++ b/examples/flutter_gallery/lib/demo/selection_controls_demo.dart @@ -60,7 +60,7 @@ class _SelectionControlsDemoState extends State { ]; return new TabbedComponentDemoScaffold( - title: 'Selection Controls', + title: 'Selection controls', demos: demos ); } diff --git a/examples/material_gallery/lib/demo/slider_demo.dart b/examples/flutter_gallery/lib/demo/slider_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/slider_demo.dart rename to examples/flutter_gallery/lib/demo/slider_demo.dart diff --git a/examples/material_gallery/lib/demo/snack_bar_demo.dart b/examples/flutter_gallery/lib/demo/snack_bar_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/snack_bar_demo.dart rename to examples/flutter_gallery/lib/demo/snack_bar_demo.dart diff --git a/examples/material_gallery/lib/demo/tabs_demo.dart b/examples/flutter_gallery/lib/demo/tabs_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/tabs_demo.dart rename to examples/flutter_gallery/lib/demo/tabs_demo.dart diff --git a/examples/material_gallery/lib/demo/tabs_fab_demo.dart b/examples/flutter_gallery/lib/demo/tabs_fab_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/tabs_fab_demo.dart rename to examples/flutter_gallery/lib/demo/tabs_fab_demo.dart diff --git a/examples/material_gallery/lib/demo/text_field_demo.dart b/examples/flutter_gallery/lib/demo/text_field_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/text_field_demo.dart rename to examples/flutter_gallery/lib/demo/text_field_demo.dart diff --git a/examples/material_gallery/lib/demo/time_picker_demo.dart b/examples/flutter_gallery/lib/demo/time_picker_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/time_picker_demo.dart rename to examples/flutter_gallery/lib/demo/time_picker_demo.dart diff --git a/examples/material_gallery/lib/demo/tooltip_demo.dart b/examples/flutter_gallery/lib/demo/tooltip_demo.dart similarity index 96% rename from examples/material_gallery/lib/demo/tooltip_demo.dart rename to examples/flutter_gallery/lib/demo/tooltip_demo.dart index 815186491a..b9b41cba8a 100644 --- a/examples/material_gallery/lib/demo/tooltip_demo.dart +++ b/examples/flutter_gallery/lib/demo/tooltip_demo.dart @@ -11,14 +11,14 @@ const String _introText = class TooltipDemo extends StatelessWidget { - static const String routeName = '/tooltip'; + static const String routeName = '/tooltips'; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); return new Scaffold( appBar: new AppBar( - title: new Text('Tooltip') + title: new Text('Tooltips') ), body: new Builder( builder: (BuildContext context) { diff --git a/examples/material_gallery/lib/demo/two_level_list_demo.dart b/examples/flutter_gallery/lib/demo/two_level_list_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/two_level_list_demo.dart rename to examples/flutter_gallery/lib/demo/two_level_list_demo.dart diff --git a/examples/material_gallery/lib/demo/typography_demo.dart b/examples/flutter_gallery/lib/demo/typography_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/typography_demo.dart rename to examples/flutter_gallery/lib/demo/typography_demo.dart diff --git a/examples/material_gallery/lib/demo/weather_demo.dart b/examples/flutter_gallery/lib/demo/weather_demo.dart similarity index 100% rename from examples/material_gallery/lib/demo/weather_demo.dart rename to examples/flutter_gallery/lib/demo/weather_demo.dart diff --git a/examples/material_gallery/lib/gallery/app.dart b/examples/flutter_gallery/lib/gallery/app.dart similarity index 99% rename from examples/material_gallery/lib/gallery/app.dart rename to examples/flutter_gallery/lib/gallery/app.dart index 0fb4dacee6..10b8758a9b 100644 --- a/examples/material_gallery/lib/gallery/app.dart +++ b/examples/flutter_gallery/lib/gallery/app.dart @@ -68,7 +68,7 @@ class GalleryAppState extends State { @override Widget build(BuildContext context) { return new MaterialApp( - title: 'Flutter Material Gallery', + title: 'Flutter Gallery', theme: _useLightTheme ? _kGalleryLightTheme : _kGalleryDarkTheme, showPerformanceOverlay: _showPerformanceOverlay, routes: kRoutes, diff --git a/examples/material_gallery/lib/gallery/demo.dart b/examples/flutter_gallery/lib/gallery/demo.dart similarity index 99% rename from examples/material_gallery/lib/gallery/demo.dart rename to examples/flutter_gallery/lib/gallery/demo.dart index b619910705..5ce8e0fad5 100644 --- a/examples/material_gallery/lib/gallery/demo.dart +++ b/examples/flutter_gallery/lib/gallery/demo.dart @@ -270,7 +270,7 @@ class FullScreenCodeDialogState extends State { icon: Icons.clear, onPressed: () { Navigator.pop(context); } ), - title: new Text('Example Code') + title: new Text('Example code') ), body: body ); diff --git a/examples/material_gallery/lib/gallery/drawer.dart b/examples/flutter_gallery/lib/gallery/drawer.dart similarity index 97% rename from examples/material_gallery/lib/gallery/drawer.dart rename to examples/flutter_gallery/lib/gallery/drawer.dart index 8b99e38d82..a5acc12035 100644 --- a/examples/material_gallery/lib/gallery/drawer.dart +++ b/examples/flutter_gallery/lib/gallery/drawer.dart @@ -32,7 +32,7 @@ class GalleryDrawer extends StatelessWidget { return new Drawer( child: new Block( children: [ - new DrawerHeader(child: new Text('Flutter Gallery')), + new DrawerHeader(child: new Text('Flutter gallery')), new DrawerItem( icon: Icons.brightness_5, onPressed: () { onThemeChanged(true); }, diff --git a/examples/material_gallery/lib/gallery/example_code.dart b/examples/flutter_gallery/lib/gallery/example_code.dart similarity index 100% rename from examples/material_gallery/lib/gallery/example_code.dart rename to examples/flutter_gallery/lib/gallery/example_code.dart diff --git a/examples/material_gallery/lib/gallery/example_code_parser.dart b/examples/flutter_gallery/lib/gallery/example_code_parser.dart similarity index 100% rename from examples/material_gallery/lib/gallery/example_code_parser.dart rename to examples/flutter_gallery/lib/gallery/example_code_parser.dart diff --git a/examples/material_gallery/lib/gallery/header.dart b/examples/flutter_gallery/lib/gallery/header.dart similarity index 100% rename from examples/material_gallery/lib/gallery/header.dart rename to examples/flutter_gallery/lib/gallery/header.dart diff --git a/examples/material_gallery/lib/gallery/home.dart b/examples/flutter_gallery/lib/gallery/home.dart similarity index 100% rename from examples/material_gallery/lib/gallery/home.dart rename to examples/flutter_gallery/lib/gallery/home.dart diff --git a/examples/material_gallery/lib/gallery/item.dart b/examples/flutter_gallery/lib/gallery/item.dart similarity index 100% rename from examples/material_gallery/lib/gallery/item.dart rename to examples/flutter_gallery/lib/gallery/item.dart diff --git a/examples/material_gallery/lib/gallery/syntax_highlighter.dart b/examples/flutter_gallery/lib/gallery/syntax_highlighter.dart similarity index 100% rename from examples/material_gallery/lib/gallery/syntax_highlighter.dart rename to examples/flutter_gallery/lib/gallery/syntax_highlighter.dart diff --git a/examples/material_gallery/lib/main.dart b/examples/flutter_gallery/lib/main.dart similarity index 100% rename from examples/material_gallery/lib/main.dart rename to examples/flutter_gallery/lib/main.dart diff --git a/examples/flutter_gallery/material_gallery/.gitignore b/examples/flutter_gallery/material_gallery/.gitignore new file mode 100644 index 0000000000..14c7d4c3f7 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/examples/flutter_gallery/material_gallery/README.md b/examples/flutter_gallery/material_gallery/README.md new file mode 100644 index 0000000000..0d13d4db89 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/README.md @@ -0,0 +1,12 @@ +# Flutter gallery + +Demo app for the Material Design widgets and other features provided by Flutter. + +## Icon + +Icon was generated using Android Asset Studio: +https://romannurik.github.io/AndroidAssetStudio/icons-launcher.html#foreground.type=image&foreground.space.trim=0&foreground.space.pad=0.1&foreColor=607d8b%2C0&crop=0&backgroundShape=square&backColor=ffffff%2C100&effects=none + +From the Flutter Logo: +https://github.com/flutter/website/blob/master/_includes/logo.html +which appears to be CC-BY 4.0. diff --git a/examples/material_gallery/android/AndroidManifest.xml b/examples/flutter_gallery/material_gallery/android/AndroidManifest.xml similarity index 93% rename from examples/material_gallery/android/AndroidManifest.xml rename to examples/flutter_gallery/material_gallery/android/AndroidManifest.xml index 3e7f58dcd1..b76c2b44e3 100644 --- a/examples/material_gallery/android/AndroidManifest.xml +++ b/examples/flutter_gallery/material_gallery/android/AndroidManifest.xml @@ -8,7 +8,7 @@ - + diff --git a/examples/flutter_gallery/material_gallery/android/res/mipmap-hdpi/ic_launcher.png b/examples/flutter_gallery/material_gallery/android/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a55cda78cb9334956103574920b4abe035ac6c GIT binary patch literal 2453 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/android/res/mipmap-mdpi/ic_launcher.png b/examples/flutter_gallery/material_gallery/android/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..eb98dc451df0af092661c34b561b729431efa58e GIT binary patch literal 1572 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?FH6BT;v&p9h2H(q(o6PCvpO4|aIBTuv8k5aQF)TY84YjM3PDmE}ar?>igS=!|Ft52i5!|s zS7y#S`}iZz*6rKhuUxT0g5#By@N&m6&83Ph2DfkDzMHrG_q=79d=9SrPq}1U>L|9n z`&i-j>h){>xfX?sY*%D^G_2w%)wq)~#F4p`oFtnIfiJf3QCw#d;`) zXU!|V6+CZVwl8c~C@I*XaF;dei)P|i#+u{{#nSWsv;9jDRX(tjdz(CSbyP_8&Rq

0nOit9%NqE0}!ZzMp z(F?W;y2Ur%<-56a!&U~aGN-IxcVt#G8{Fc~y?@|~OUn0xdX~ddcmBkQW^_NDJo({V z=MB4ga>~Nw9De>eeENZ8$C^Ep3gjBB*FN~zGX4HW?moHWUOs$tjufUVrpCVi+%R>i zq=rk0v`sDR1{jY_{ICW>Up}=QXvWg-j84FZT1FmrBSgd3Z=m_nYY9 z7KZN%GnyZYdh4`2i<>d4i)R7TuN$6g7TFdu{LuaKPMWb{Y1@8*x{rr%pWIN)a7NW= zf~_o@?1v}opK8XJ325~tymXUcm{<4ZnfJnG-4$+5TqWWT-#OltG^}P{7Oxv-lxV$W z#s4Y4TP52V+4~R8`@7(EA=}3r#$TSTSBma&`XTzk*LfxLCM)q}myhtg@NS!T??Z8F z+Tn*@CvMx7s~wr%`bVwm_I86m7Jm*oHD65HVLv<4>$1XT;gCNX@n*3XexqXbtwsPf#nM`Z{PI%ie zg;7GT<%o)gZu_L#37h_OnUpm|n{SAE=UTqfJml?s&dk|~7x?xb-e4^pbMt{-WWW;F zO*J3>-(al!#kl%wT?xbIt+%2$lBA#HwaH3Om}MF~$JIKCeMfNr)e37XhN(=kc^W!x zdz=DV=gng&W4;o+v1qY|`x}P-TN~>B=ovMf6l|jS+mw2@0ZUvlFw)Sy|e*OB-pFcx6IXPEtT()bf;gPsM^I5Kc`&naC@!`R%e}8}5 z&wML&w$$I5vE$RHPm4Z3KVSc_XeXa^+rrZ~kA?iv(yecMFl$h&7@?0MGQ;ZA@3=E#GelF{r5}E+v8}I%A literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/android/res/mipmap-xhdpi/ic_launcher.png b/examples/flutter_gallery/material_gallery/android/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f1783dbbf3c9fbf1b5580e117fe6ebb201c1f978 GIT binary patch literal 3602 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/android/res/mipmap-xxhdpi/ic_launcher.png b/examples/flutter_gallery/material_gallery/android/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..46828a290a7c26895fd4d51588079812046b875c GIT binary patch literal 5800 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 QFfcH9y85}Sb4q9e0G$6UJpcdz literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/assets/flutter_logo.png b/examples/flutter_gallery/material_gallery/assets/flutter_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b795ed72d10ee03f88b95b5614f149d4877ef6fc GIT binary patch literal 5666 zcmeAS@N?(olHy`uVBq!ia0y~yVCZ6CV2I#gV_;y=D$I9aU|?V=cJd72;Nak>;YjIV zU=Y3O>EaktG3V{v%9_xtTO0P5p4<7H&(p(+?U0Cvf{K7hlTR0qU&PwtwNdR+?Z4JU z{eJTy?zQx**AKF@f3Mm)`I=R>?5a>l$CP7?EbMGE)14YvPE-^xFFsdSAG4vubBE_U zkq^KB{%D?4doJ$zz0&LVs^4zCCbsWE@RT5_f@#9fWULQ`++D(SP;{@y5x&j-2g8h; zXCBBAyg4VRadO9!sD=^;&8gjo%inNpXO%X1eQmy;gV6o^MolRhe>Wx`%=KmPHy%_w*f&)u`K%Z~E)q_YYgI9j&YXrXXPMQi&Zo4l<7JKv>lnzj1z_cu)wS0svG>?&waJoWfvbUGGRD1BMw=B|Fs2ugI!WwKdE-eA78piW2w?AC~g-Cd5e?;n`EX5lj1 zS9XrSLMF~Oo{`VIzwhfl=eS2+2~jFeQ;SX%%Y0%G7Z9;nA<`?yFTZ%BRD`b5*3QcA z$7dF4EOon~DE2PK>D{{Rm!G>o&~7ojzr?fH(7|Pvb=K-BQqnvhYNvN|NBzBV_4dW@ zp_2u9oHRK4c=g0*$Q4vCC}(`wWXDqU$*^Q@N9x8Suans}1h|+TeJ$H3?HcISTdZ{E zwh8n7eW5Q_PJ5oAwf@k2^Pcxzdi>iL|`Zk$Tqb~sa8?D5?noI)SU*YU@z@n|$Y zQrt3)=jcVAZ@YQ^Et0fRRoe7_e7p1%i=Mg@yaACQ<#UOcFwH#3Fq}H9tv){SJirOp~B}T#;@s1r>x)m%{D0T zO~)?lD+hkQj$d?F+}qv7d7)sKS8s5^=RJ}Y!Mc~9ZT;|rxuQJh(d&l-tEU91=5Bpm z*tKZNtR*@BlD}U5F~?)o(w8#38hKru9OYtdr1R6K@9$I+X}GEXur^&!wSCIdGmCG3 z(Qpm)dTJ&3Z{s`FnuW_kyf0Vo`N>isapTsZ2c`1M?>i-ZE!rY^ev%}gp|k51OZT|f zfn762Cl?b&)kZg=?sZU2YdxA!bk$~yIM|91)3 zjfY=FKNMS*H@DaN>ZTIba{UXwF;{PYd~2zUiKCI{P{vg)R+Y{2~BKf}vgU z^`B(y)cxX4rv!(zu9ewxbaT})mOW|gHGkwJ7b={06e{bV8pIaB@rAi4X~$AYi#2>q zbENn_&t{(gfb08#O3sFi3-wA_r`iKD)_vM_Yf|o}gD-c4&14Wic3B-8l16 zi=?iVbHI}*#iog2hr$@x9V}nSJQWqwT_rQCQ_=mFCG-7PSv>vx$L?@iKXZC}{Nog> zk5Bp;Ot!GD|IWi*Cvm)O>gf-?^AGXf4H8*8g&}z@N4)Ut^*0qaNtGv><|&_!?-sLQ zILH>jXZK>(N!{H-WmgZ)$_<#o9q!Y(Ch5j6D~;XOm(j zU(9L0ynBg8yU3Fy>l3wM9gAwUKVDgPFvHj3hR+HyEGJUM4nFM3zhKVe_Qel0>_@LXby!q~Ki?)A_UX}P_=7t9s z{vQ^z*)DKSj(Krj%T|AH41eLUNmHu9X`|6I!(h#)TbW+zhc&oL z$0xsFulLzAiQ!6qHDdY6FYi9b6C-;)0M3!Drus-o>*3*!6wQ~7d`+EM$A8IL@ zU{*K%wE2NOQv)h%O>C87B?_drr6#VgvcEd1r1xL*gC~V7zUJnK4Q2AYR`OUM`4gKT zyyNTID@PZag*M-15^cVT$GlM&Qxqm}>`iocw@i^br z4at*#)i%}#rwcDMbrzVG+<*ZwleIbj$7edRYlc!}5GkCcJU$;qpA+58WG z+MbXfGdId|ms6No%~REobwW9KYvvH|oTD*1z1h@;6tQ z)@%~jTGzMEBB*gDYwfXwGqW##UgPN}7gNg3IDPi~&J&Z}>wV8aTq%ccU zdX@O0FRS`)pN-?Y>Zq~b=+zr9v*zWA=GT(n-kJ4h-)`rN3_D(lH7#q8j?I1Iwf$$H z*3wflv)?R>?G)c&{N^vmr_Bigfydv*)rv>$38-=`dScb1F3#oWR{#0wyj0(=_5-Qc zg$?fB$ARi!=iy?J@iX}L@5j!fB<_+4m5S~~8q#Iw z8oAZBy$!dV)O_~Cn;MC-%13**JD)$i?q1*B8xwBSJ#q{)i}~sM=dhd6{nQ{;rQ<#l znf{Vav*y(~pHF;c$7sv2IBA2(?yQHsPcNo!o>}?kTkOJc!<28%v%h}-vR&=4+oE-Q z=T4hrv+wQ4Q>;ptgihDK)%05ZPH}DWo$|A-n^zs^c(^)pr=;CY*3{|hX{sSsvemEM zIF=WF6~5cBGG3|VTI-wgnR8NSeTqnbm;XNb_MAwUGnFe>E-18S`F0?4>c*|}x5`BM zYW#~)a{7Kkj%Od!mdf=@-ye&2jNkE&Z&rJM;+ij6)Op~W z`Jyn_{=yY88wIzSJDmI(`+j@5_E0sw_2wzON;_@at z|M>mo^51v)s2zDE{gOxaA6uz;`Sb8c{%z@-cjr{{s`WMOtK7Ji-~GW&)__k>Uo2#w ztGHe!CUV1v-Ye0Q8f!Yp(=T?fu8}NS z*`cE2@pXp2wo>|@M`|!qJ?VrjH-w#>mm--%i zr^FO0T)1xkCc4EH%xxbHhI1!a=QB0AKwqoOD%Yrx$*vGp@!?z+}aiPHdpLBG*LlKC-y?!Y?lW{ ziI;A+=mZxxoIE|a4EC_g(nBj^;f4^x}=?9DQ>H?I+RHt&1k+xrdEI&==| zDI0uZi-==>zqa@9wr+LD`35<4D|_9u3?Ayu=?`0=8!ciVXzj$J<+f1GUtQx+be{h9 zt`qZ~eEAn?)pNuur2p@vgogUfxvO4%7rqtUd;EUS>1_))=s&D`+`%)a=Vio-X6cRJ z*B`&SLG(?*qd&|2|and zv~#k!!g_&oI~eNg1b_QZp6!~FmsH);dtS3EC@Vqb$mD-weltJwZ~9iIczSKQUC%6r z=Jur2l!dnwSKM#eThHuvc-xb-FTDHtu3b62D0Jif;-euaRyF5tUi|-kHCNVynHK!_ zr|+l`&S&$nn*CtI#1@ku6Q4a26!e_E_SkuiuArwW$d;$I*Jo)Up;X9axAt}H$Jf<@ygl{pMq{|vffr*legn>(2XDF8S5H5?>q0^ z%@Mg%=ijH7Rv~lSOuv;lG4=1b^JmFw>ph)Mf?Wf>dbcZ`sekNhv`xLhE_YTyAgl9f zMf+72v+Cu~{qukD;M$8N7Wdkno=tIhnfhV5`{(L%X`9Og292dv(PGli_xQX&n?3pUw6f}i9~lxsd_P$&+N9TR6${rQd9t%FZvE1Ira{9A9N>aX)-!tofn=<*jtLD^v z*Bf7N{H?gObke7bB41h)ry3LpXsPoreVOrZ?~1nE3o*SW*N=o%o;=fYEx58&GN;3E z=i5)2EXt)U)6aCR3`m?U6E@+Gl2nY^edd39N|{la+j4mxOnN(e)_9j@h0e1* z{m=VOU$C!{{v#{*>02e&uR~WpXXw6g-hBG(To=(L?hz9fPYiId{dvx2UH5Z|Ib1gT zUOd^bgs1CQ;_potru1%kb2Rf-qsesz->U*2o$nQB*zy0fG2V9aZKW{h?&uBT`vq?+ zvhOWQJY*7e+D+hMOSNe;`{b?alQouHT|ezymd>w;8He zE-*=#C-+MASJfLnyLjFERN|iyCd*0_Nh$kFu{O#|EAJfXuomK5`Pcvd#68dCCU8mS zmoV$?pSjCcH)Y?Z9gh=J6BKJwjdcD0P4j1#@Hz$ZUs2WNgk3-VAKWbYwCtF$v&o)` zCg%#gRkpGIujpyg&Rh7?Te#y)+_it1NmolBd`oyDmLUGsS>C=^ZGFG(vf1(s>%U*| z%v#ftyYhnb{v$d0hu^y#n9Vr7ra8e^`O_<*J8yZN#r>2lmNeAvoDFJC)BHGnRw~If zh0i;nUAN<@QdIT#Up2E6B%)?();&0Wr{aJ8s!vb6XIhyYS9|p9j?KR#N46zgHL6+G zbX!lgycW<>Y3UL#sZ1WPfp0 zDtKzoW8vwXqUw)(=K6Hs_THQMN&CTDhmQHLtR#8 zT>NR)_1UHH`&|2p?LmL_IuC7-jq?58xl*ID)!ya8z%wSkb&5*zG8dm5iqu~b z?5sF%_m8M`toK9(r5yy0`bVmuJn0@WiiUaye-nXisZGS)UYv*JOTZ1V{p>d3dzrXR>s?q6uec=`+ zw|Pzb;|-HsXT1IPNj;&l@PyMA?+&XwM;3axop+lObU*&5oqhBaHPKa%J?jKR`WBY{ z&=A>hwdAwFhdmu{`oBtYsqWw1ZpG|&ude^gfZ2JAcm<3p3uo|Mhm3{lf3rzbmjD*mgBG`r60Kk^0Nhw`O(B`(u!y zk(Ht9>-zWOO|jX&=I4d)=D&1#^g_I(^>E-1%dnPL%l|vL1gX=FG@s9-ea340?CTdJ zICS2=EL?V6*nRmFzRgN|?CaGcUxy!CAJLO>vF6F4x&V^~hy6)TmU|1^53eb#u86%n zgMW{{l6nS5=&#FRld5)#rXB1%o1$OI9Usi2$?N{;tLx$m)z6*hGqU{RSDP`p+gvDd zdsAwhes=?ZL+J7B8xKBu%znApYbB5NnSR&DeaxjT+t(<6PSCCT5g;;$qhilRkVMnU6_+uD%<2?ivFF1B0ilpUXO@geCy@9PuUq literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/assets/section_animation.png b/examples/flutter_gallery/material_gallery/assets/section_animation.png new file mode 100644 index 0000000000000000000000000000000000000000..8ada8cf0c1b6983dd50b137f3e56279421edc19c GIT binary patch literal 4221 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/assets/section_layout.png b/examples/flutter_gallery/material_gallery/assets/section_layout.png new file mode 100644 index 0000000000000000000000000000000000000000..808a1fdf5ba7d74bdb79b54ce8e8fc1a80b17ea4 GIT binary patch literal 3765 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7a543edbdd4abd8835a0ef3e7d561801dffe1394 GIT binary patch literal 7707 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 E0EnXM*#H0l literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 0000000000000000000000000000000000000000..05a826810499225d51642e35b7bfd6809d555fb4 GIT binary patch literal 2763 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 l33?*VdZx|RD7>k44ofy`glX=O&AobtV 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png new file mode 100644 index 0000000000000000000000000000000000000000..3006f1d348c1633d4d076ccf82bb01cec4d92480 GIT binary patch literal 1293 zcmeAS@N?(olHy`uVBq!ia0y~yV9)?z4mJh`hMs>rav2yH7>k44ofy`glX=O&z;fKv z#W5s;^X>Gz#loo~$L6c}{<=G5n^+F3*TSu9SsABti^}c|kod|b+xGFC2nGTWMtPJN&Fxzprhfzoa=eW{kDqlwKUz%yL? zFLy;trgU_Lbh5T{Hp3coXI?gGo@=Ka_I}>Jmu>c|yNOT#Tq)HwRh`-uRI~nyxmxSu zsd8KG+qXSZiJUR@pQXAgV?+#_%ZfjXe@rkb^U8X=R(6K<;=G2<`@QSym7hNUnrL{g6KsH?>S|TAiK# z-^##KX&>DG%En$|2&(wFz~qGO3A3{g?xemv74COJKr{9JUDCY`tLs}C?dMO``{OZ-G3m@rncat$ zSZ28%`MlMB$>w;E@9AOBZ(ZJ{8F%1kq0=ebq9gf^vu`bl7IBjJ+j8MjRhoQ}?%hlK zH683C;`7-|O5=aMWPf?scy%B%qu!&6&(WH-lSLF>eG*rG(6jNG*fBN6z0x0*|GbgC zci3e@YtO^Fmu9m~p3Tep@!jV6*H4URY+X*odtI|qdb29(&$5+!m%RDS^w@f-=ewD^ zS=KUT&d%!f=KQmnnl_=I(W~=`z{?~&^d7Ii*3@+u*k1EM(Yo##oOxbt>@wlH7&b;Wz!4hhMkJJcOvff z|Feo-`D95+{){W1-~9WWkT84Yt;`v5kGO8FI2zq{*KAA8BjJ~CC+8fQ?r-!$@6El( zzgOsREu1A-e&?NPnrmLM*MTI#WpztCjFjK}J9%tP(dRjG<-Tf+D@!A#D?P3L?lk#V zlv?tBGk-$#e3M^{JPbhwflYPVeEpK$20NrR-#DdPM*L#Ee?nm0h9u4T%Ov%K6Q-u| zJeTZ0{I0WqX}{gnUGs~0etB%Y`!s`BRm;??I)lkWu^eDL3eDaa_UYXMljDD^MJ6$t%yreY@Ln$JBtJF2 zyHa9LMcl5B(=Wf)@tF94U!%$7YF5wD7u9b!T;Oz`8zNoG7<-A4LI2I9b%$Q$=WG&R zz$#(fusG$>3+XvKtIzB#`^?~TZc@;B>HKC>-=&ELsg-OkKcgP!r7PPq$T?JV&UmwY zuZ&alIdp!5)cF{?((W&#yk{#18T)HAE(Y*DWANvWu0})Txec8G;s+PI1hQZw6 z`OIB5o==QpH!nLX#gM&7`@qhF2@IO1d$SB8gku@c-JW;wKVx5dN|$ceAwvcR1_n=8 KKbLh*2~7aX&0X~X literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7d22d364df330c5ac4ef603ddaf04a42b95e99 GIT binary patch literal 2952 zcmeAS@N?(olHy`uVBq!ia0y~yUk44ofy`glX=O&!0qJe z;uuoF_;%LM;?Sp($K^LU2nlU!pCB+z!i<@NNvx|;%Ww77zSuQe-}+3S`K|q*``?vw z&z1b@UVFJO#9bsuP-AO=W0wY}w}Rs|2O))Or(ZwsO>S1S{C=mT75URw%DuJzcVNxe_i1yFbMizT z4T=Ar@p;RBtB-TJwDt*^{F^D9w%p$2^*bZs30+Sn$=q?aJGf$p$Ty*@;p>f~KhB7B zWXns)lQ`kV5_jBCe^u4(q93O#xGZkhC5J_LPGH>QoX;e;;MpOIjd`myHobn#zGPF; z=B=~OnB|&lubpwr>gRh)#sIbIj}6;jKJo4@OP_OM&rfj{(HUP9AJ>2AJHBbdVva9{ z5xaIAdDFRmVb9$sbGt8n=M#K=iC<``>vhXN_Y@DD-t@V_XIiuLj?%--2KtNgKcB7Q zu&;b$yV?GKpUoEIzvt3K9YRIc&ImgsZux7^%IMRq8*G{mUo7Vob9t8e^YIlv&$`v~ z|13UG{g^*(dh}$IIXi5s8Tw|-{l9wVDdYPWm&Zl@*ll!Q=+th%8|5#J8_qE87QNBN zcIIB4Y*@ViKC$O3pLDp-%*g5BpB4UPGRG1ZryjTB3olG>O!vPMe9ORXc23g@%hT6p z%c?(03l^#Q^;_b5?dItolba&u3N|S7+^TIn@4DG;i(QSl0IQtOjF|0NPOdw%7Ttcx zq@>c$X#IWWT{|CnhVyJ4O!=O&*^Y_xw^s+6&sNaty1&Rv>S$BStzcE5hQ$^)`s!!K z+IMPxGZ1;>-M|pQzxD8cpp` zO;+9Y?uJzjHVyHyr(+nZUvIm~cucGQm@)VLH<#BxxhQrkQ_)CA)a&)<<+kf9Y@YKR+ojm>PN5XDa zvrNp_jdp!%afePU~N|AY_u*0Xwss#WQ_{Y>mYjqz>H|EuCTd zh}k`Ify0{vbNY++mYFLr{-~jJOmwZG^>=%J&A?yFvQ{T-WO3d9CwQ~z*_BaM-!Cz( zX!f03wxjFD?b<%0&R~K2iqDyoUW;ahZQ1+9^I77@M3>irC$HV>tyi6)`q@A6*r(ek zdV3~#nwZS``(XN#FZt)ky`ZV#wWntiXOiO2M~k}Cq{B8vL}&x>3RTxwXnhH;Xol#~a`N&BWFFV$~(4 zh!YR0xTakQy3nT-H~GJ`s{9?cW;gXe^Lzph$YdQ}|Mrtig;DF%g=g-tF-bS5pA%F* z_uf2w%GG(Zw$Ix8OMBkhf@w24m#_w?#eBaao^vu~(#hHoxzc#WrHWP8u2!VZefQer ziJs_L!Js*><{s1$IWaZc@}K$-4UN=CziZ;vukHP?N<6cBD?(GadPQ`ER1#vi%8`>7DZhI||qXU7y!7)oSbfzqtPF zwcIYNLtnlvWC-co`Ylyr^Wo&SMN7T5__)q~alBr1p84%dKU^IyR&Z&l@3_a_aCF0w z`R>JG>kgMNMw~ZW#9}sc^`*&HP1nEI=Y4xq{^4MV>&*!#)Gys#t8#GpN-wK|M@s~f zb$l4qg(4d|RemhE_1wbfP|ogm4=$@+S;;$HXiwa#)OF>I6CI!aKJ|Up-tYUCA2IlR zA|{k|>Y@%=-8AX#JAa;CVCl?QA%DMwarxbweoI__yJoCkHmQR%`WRzjgVmP#D=cgd z zdrPkW;WT!8^URZ%|M_w*F#8hk7w;$6ShzQ*@9xXV9`--kDt^=pW*AO-8IAM$#anv zvosFQyLI};=^&GHht@7($XeL`ZT8%xk6z*;s>{0?Lab-bDYCJhAh_V_hRtgx_)fmr z&-h0`ZBCoxsLn{qRHy}P##>k6~A`B%>|ZILn1{^+>WqwNO^}t zmlP$eO5__DBj2+6T>YH(n{k8q^oPHlXBM3nUSc8t*lArsEmMrVxahw{KR1bn2>DkZ z-M?O9|5=|pb=D91`;V{DQ@LI-!_}89BrTMoqe^*!jKgV$?Gh8jnJ)aWJrE+0c!Aye z%)hqz-Yn`8OAWhTT)&j?Z9eln>kD`63bw}7e|jzQufKYkbXx4qoaTGWyJa>oxlg$1 zmp}JU*9?Q1hF*2-i4S-q)B;nc%3poyUMYH?VXMgHd+d+-=6pGDS)x2q>&LB4RdLKa z&&*h}i|<(O&6lA9lb>JMv03vV!y&G#9cye?D;a#LTp{7JOWyVF@j2G|)!$3@Ph4^-vR#&3i~&FA9h>FZ?XkUY!EaCD%)M8C zF27%O+#yiRR?^_B_L3#5543aYZ1nl(>-ulH>m;TXymHnr_G+uomta|R!0XDPU(Xi5 zSb04qbf2#3OVP_;);?acMt$mM7iLf2h}XA&^71R})v`VjI91;3vFMiqkDLh}yZ+Xj>K9>5bbuoa^Elu-5*O!C#nqPmc^3q_~zv@BD z&GG_Op=IfJ)EXUl7AOlQF(fm{3KqPPGd5tmAjo+9ogp*v0v7}i{AbSSPyBK~{LDE9 P1_lOCS3j3^P65WL{& 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small.png new file mode 100644 index 0000000000000000000000000000000000000000..3433da11966752007a87523c4804e71f51fc8547 GIT binary patch literal 869 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9c23601cf477e6733d327084a1b626a283c88f6 GIT binary patch literal 3216 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5fccb0a995841418e8ac7a872aeb500eabe652 GIT binary patch literal 5057 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 O3=E#GelF{r5}E*`WIUt* literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..40a701b5146efad1146d345afeae89c60dc71b3e GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z?kgm z;uvBfxOMVruckneR{Qrer@Agp%}Di1Z5Ep2A;7}>O1HWtIE>QX#q!?KN2R@ZSa+tdF4wo(79^!6P1EBR#Jf!)jt zl}|iBkk$OLQ}5K5=#Hi49x~2`%xa!D-Z14HE@gV76w&QaBR@w^aNEvJo*wZB%LU`+ z2CQBYxxQC4)TKbV;H&p{qnNmcdeKACx=m4{@B9`{VB5^<^?Aal!@rm#T)wPXahl28 zXk%B&dx0kDwvx+@kg^$8O3Td^~y6ZI5cVRo;voEeAGhlv*CT!u@i8`L&1>t0PO2Zyiv$swly7<+k;$ h{TEh$x&D{k;$Fu4$#t&|FfcGMc)I$ztaD0e0sysZyW0Q& literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..06c1a805609c0f9ab826ed1927860c4f042941e7 GIT binary patch literal 952 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U@r1> zaSVyzd^_!?_mo7DWAi1`3uhK;Uf*|N*dc5&Ql zX1SBpz<+w_@sM_;;9ocV0-md%_ioV6^Kw%%{?h^|wS`N_BF z!KN=S1t-=k7nO_LQTXmOX?x7Bg89|0A~U9lJy+fCzG~g$RnzBK3eB6&bbJ4jiS3uF z7z$*T&l2`OD4NOp!1LSQ3a*v0M;v9911~Gg-QVLCyK;HN|8!P~8;kjuwD#Y8P&l3M z+mEWH(+^*IS0-Y!ZyUFy^snc?mi%L^IpTDF<$?FAnUzkPe&6GpJuz>sSCrECxRm4J z(`FV=uB(}~i=$|nMy>as+80}|l!aM&UYwOG$g#)qQ2M29qT+2$f=2?nO=5a`<`mSo zMx-1RTb%Zi*C`=SP1#1v0*ZN5p z?oT>jAbjN8B=y5K)mlq4J!U8E%xQoBwf9o*?x30WJC%DIwoVD%to&Acc4t|-b5^Xo zx)e|=VDG!w1{{G^!6*ICj1MIZ6Zc!6swe;O;U~PNi zcA(B#rxYGZ+byvY&-E7ZJ6xFeIL$OMaQbGm0{2~Y-dcLS>($;z#%}mE*Qx4I;-Za> z$$~Ci2aC>amVWSk!W{Rt-WF?q`h0m(s&ZhP#7hCKN{`U={*sSbyPkNyco8hs_%ZM$ zbEuSxlzpZC@=4wui#k^E6-Q=sK963WY09xP;Hgwsk7HG*WWv@2&5XS1zkV&YJkN5b z#=qp?qd6u&B>rF9Z{gT*;x6+5TkyH_C5s=3S`!Dc|<4uhy>DORcV~e0oa!PKO%Dj}}~G SA2Bd6FnGH9xvXPn< literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..1909e275118bcfa992bbcaac677508cf3cf57fe3 GIT binary patch literal 11759 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 O3=E#GelF{r5}E*`WIUt* literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..69c96ef1e27378813dfcf93758cd1ae569077aaf GIT binary patch literal 29082 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 SA2Bd6FnGH9xvXPn< literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9437146039dc8f0fcffe07d92750b3294feb92 GIT binary patch literal 2237 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z)|k$ z;uuoF_;%*);*eCaqv7v3ceX3A@OUaHNd+8y9a5<&e{81KTz1{{`o^LAeyIPn@DH|& z3_H6bH8F8zM1{C)LIR6ZLqTUul8}c&iPgVrmNJ)1zI*zqzr41oI{fR~Iqz$p-_BmY z_uD_e@UzKU$*c8}?=xT5W(bi8c*YSDwBQWq0xo7P9*traEzN*uEGs$^ZZ3Ctn?IMy zTy5#>%R#<#uUyazonGOpy6-O2oyW(QUOd0_WT2+4cIed>hLZcrxiu~CbGehdf3971 zAhU{e96|^-7l*w$~_r(6gWuTQ=a*4 zSLQ)&IW#DL@YKjp1oJbGn!3Y=LWZSFZY zD`n5Zz*Vcy%T9jcaglLG^2Go3?oz)Qk8?+)i1x+)kF@$eb<5M47ewv%Sf8?K-#_`7 z=h7>_2a;lx8MaI|oBeCazTHc{N>AP)*Qc4qW%0@VzTTam89&n+B{%%$?R)Uz_XUV` ze^V1H_m;zD%En_y66Q$q#qW(?s-AHEm+#LQ{{F(q!kjnNr)0SGTE1CoADnrs>P4OF zuRqGqPIXkByV1jJ+H!UMW%VW7|7*%7>K2BHFr*z5*zn!yVE69ANss*+!#@2yV1DV! zkxM1#=4}=eNV~YeHsiv^!#C3p-)CLk@VRQ5Q5kdAxmfKSj<7^RC|A zdYrfCtb#?7>~~Lj$J_sMFPWXXE-EFby3gAn^h4T$>x*6-7GKFWWzSQl2Pb(BnJ^aL z+~SdTYm&G3Sr2tPj=A#}zlo@A?zrDo^(^I4#4OhDmk!oe@+{cqVa@pDQ~l1glh$|5 zf&;EUU&){zF7P+QZTe|h{zIpxy*P15{l<~mbM3!~ZT*pbOdvDZXn|$lGvoQQ_qlwr z+_|hX+dbgDpOWQ~r!FQdEq}djDF0)#^`G0N)t~xzcYdDDzV!Hi88*G@D~lNB{E}c* zo76bzxW!!ChccOg^=?u-nx%_AebAIz_%%qq#E*r^;X3oZ-aN0H9xI;R{Og`%;2*Rcd&kbnZ7iA-g(izXEy$m<8Ju8_uh$( zE1b^i%s9gMK27;ctl~Gpt64`@^szphef?toU9Yokj$O=}X@-5fKL6#5`1Z$sNo;+W z`h?-y8hXnn8$pAU14{aRQ4 z_vAP9|H8ANFWLRvh43#MFTdvcdZ5o_A+K;wwtlRFR`)usJ-ykx=QH1UDIP!loy>`y zwTqZLw;itQdD?qc81jBe-H!ey)PGMmR+@8hy(GhH7Rj6E>Xim{4=)_L;O(A>y;AY^~Y$DB&%SC7*Gcdc{ZE6S)k9 zy`0}(#e|>U@k@OP|G7oi7+yRUJFd=NQP8OH&e`Dj#h#pB%PrHN?@m13+&_8J_v6i5 zWE?&*efTSW>0bTj46noo4%g1G9pZkh{NiRb!=lZT!?`Pa7nhbKy!4d$+U>FYNA9a_ zOt*eGUs}F|>2Om>#=}|5f34(uugCEAc4giBM^-zZHM%cVJhi;IZmTXkL-*UN#0$cg!WaloJ)DXh!<8^S7Skx0|i?44#2Jqi8dHd%1oqiiF z_5ZnLdzc;Wo_x!&Va0Tg^XuMOx9qzcvwCkS56io6!5jD6T&v98{32FabXh@}$nm*$ zd7ZNv7xOOLB7F0psfpK%lZBTKUhj=jI<@2w>y|~_4SR~EZ}mQo3C=mqcz}n)C6~3l z>{d$GOz#&gepbil+FfN|THWzxkK=)to(%JsCRV)*H4E%Wsuf%z_x#-29lCS)ie|e$ zI=m|CfY6Nxc6S+MozklW4#!S$zyI3m%!?OowFVayrk*O2ND%#&QJ7^cE+~xf5(g4Qs17(mehOSJa&&^{n9qk zr!{;G`%e3b-1>ho_Mc`>+al}Pm&z=JRxZ$1nIF6B&5>hvN`14;1D|mjHt$^lDbp|My)MqysppPI8zPoKYX zSMLAB98ZRS9_OBYZhfPjznUT7-pBO#AjSn}1Xma=IKvrmvB8TARNV`%SmH2K*kM0I Z73=&z^?MEWF)%PNc)I$ztaD0e0suRyU3vfj literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/examples/flutter_gallery/material_gallery/ios/Assets.xcassets/AppIcon.appiconset/icon_512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..69c96ef1e27378813dfcf93758cd1ae569077aaf GIT binary patch literal 29082 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

Xh|2tSPwbP;VKn3fm+y7TYEGxg> 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�AXIGbmc~Oy}GBn#Z@6bHBL~ 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 literal 0 HcmV?d00001 diff --git a/examples/flutter_gallery/material_gallery/ios/Info.plist b/examples/flutter_gallery/material_gallery/ios/Info.plist new file mode 100644 index 0000000000..c89ab01a94 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/ios/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Runner + CFBundleIdentifier + io.flutter.materialgallery + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Flutter gallery + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/examples/flutter_gallery/material_gallery/ios/LaunchScreen.storyboard b/examples/flutter_gallery/material_gallery/ios/LaunchScreen.storyboard new file mode 100644 index 0000000000..78686cd075 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/ios/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/flutter_gallery/material_gallery/lib/demo/all.dart b/examples/flutter_gallery/material_gallery/lib/demo/all.dart new file mode 100644 index 0000000000..a2c41f923f --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/all.dart @@ -0,0 +1,37 @@ +// Copyright 2016 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. + +export 'buttons_demo.dart'; +export 'cards_demo.dart'; +export 'chip_demo.dart'; +export 'colors_demo.dart'; +export 'data_table_demo.dart'; +export 'date_picker_demo.dart'; +export 'dialog_demo.dart'; +export 'drawing_demo.dart'; +export 'drop_down_demo.dart'; +export 'fitness_demo.dart'; +export 'flexible_space_demo.dart'; +export 'grid_list_demo.dart'; +export 'icons_demo.dart'; +export 'leave_behind_demo.dart'; +export 'list_demo.dart'; +export 'menu_demo.dart'; +export 'modal_bottom_sheet_demo.dart'; +export 'overscroll_demo.dart'; +export 'page_selector_demo.dart'; +export 'persistent_bottom_sheet_demo.dart'; +export 'progress_indicator_demo.dart'; +export 'scrollable_tabs_demo.dart'; +export 'selection_controls_demo.dart'; +export 'slider_demo.dart'; +export 'snack_bar_demo.dart'; +export 'tabs_demo.dart'; +export 'tabs_fab_demo.dart'; +export 'text_field_demo.dart'; +export 'time_picker_demo.dart'; +export 'tooltip_demo.dart'; +export 'two_level_list_demo.dart'; +export 'typography_demo.dart'; +export 'weather_demo.dart'; diff --git a/examples/flutter_gallery/material_gallery/lib/demo/buttons_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/buttons_demo.dart new file mode 100644 index 0000000000..70b9922a31 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/buttons_demo.dart @@ -0,0 +1,196 @@ +// Copyright 2016 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 '../gallery/demo.dart'; + +const String _raisedText = + "# Raised buttons\n" + "Raised buttons add dimension to mostly flat layouts. They emphasize " + "functions on busy or wide spaces."; + +const String _raisedCode = 'buttons_raised'; + +const String _flatText = + "# Flat buttons\n" + "A flat button displays an ink splash on press " + "but does not lift. Use flat buttons on toolbars, in dialogs and " + "inline with padding"; + +const String _flatCode = 'buttons_flat'; + +const String _dropdownText = + "# Dropdown buttons\n" + "A dropdown button displays a menu that's used to select a value from a " + "small set of values. The button displays the current value and a down " + "arrow."; + +const String _dropdownCode = 'buttons_dropdown'; + +const String _iconText = + "IconButtons are appropriate for toggle buttons that allow a single choice to be " + "selected or deselected, such as adding or removing an item's star."; + +const String _iconCode = 'buttons_icon'; + +const String _actionText = + "# Floating action buttons\n" + "Floating action buttons are used for a promoted action. They are " + "distinguished by a circled icon floating above the UI and can have motion " + "behaviors that include morphing, launching, and a transferring anchor " + "point."; + +const String _actionCode = 'buttons_action'; + +class ButtonsDemo extends StatefulWidget { + static const String routeName = '/buttons'; + + @override + _ButtonsDemoState createState() => new _ButtonsDemoState(); +} + +class _ButtonsDemoState extends State { + @override + Widget build(BuildContext context) { + List demos = [ + new ComponentDemoTabData( + tabName: 'RAISED', + description: _raisedText, + widget: buildRaisedButton(), + exampleCodeTag: _raisedCode + ), + new ComponentDemoTabData( + tabName: 'FLAT', + description: _flatText, + widget: buildFlatButton(), + exampleCodeTag: _flatCode + ), + new ComponentDemoTabData( + tabName: 'DROPDOWN', + description: _dropdownText, + widget: buildDropdownButton(), + exampleCodeTag: _dropdownCode + ), + new ComponentDemoTabData( + tabName: 'ICON', + description: _iconText, + widget: buildIconButton(), + exampleCodeTag: _iconCode + ), + new ComponentDemoTabData( + tabName: 'ACTION', + description: _actionText, + widget: buildActionButton(), + exampleCodeTag: _actionCode + ), + ]; + + return new TabbedComponentDemoScaffold( + title: 'Buttons', + demos: demos + ); + } + + Widget buildRaisedButton() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new ButtonBar( + alignment: MainAxisAlignment.collapse, + children: [ + new RaisedButton( + child: new Text('RAISED BUTTON'), + onPressed: () { + // Perform some action + } + ), + new RaisedButton( + child: new Text('DISABLED') + ) + ] + ) + ); + } + + Widget buildFlatButton() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new ButtonBar( + alignment: MainAxisAlignment.collapse, + children: [ + new FlatButton( + child: new Text('FLAT BUTTON'), + onPressed: () { + // Perform some action + } + ), + new FlatButton( + child: new Text('DISABLED') + ) + ] + ) + ); + } + + String dropdownValue = 'Free'; + + Widget buildDropdownButton() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new DropDownButton( + value: dropdownValue, + onChanged: (String newValue) { + setState(() { + if (newValue != null) + dropdownValue = newValue; + }); + }, + items: ['One', 'Two', 'Free', 'Four'] + .map((String value) { + return new DropDownMenuItem( + value: value, + child: new Text(value)); + }) + .toList() + ) + ); + } + + bool iconButtonToggle = false; + + Widget buildIconButton() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new IconButton( + icon: Icons.thumb_up, + onPressed: () { + setState(() => iconButtonToggle = !iconButtonToggle); + }, + color: iconButtonToggle ? Theme.of(context).primaryColor : null + ), + new IconButton( + icon: Icons.thumb_up + ) + ] + .map((Widget button) => new SizedBox(width: 64.0, height: 64.0, child: button)) + .toList() + ) + ); + } + + Widget buildActionButton() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new FloatingActionButton( + child: new Icon(icon: Icons.add), + onPressed: () { + // Perform some action + } + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/cards_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/cards_demo.dart new file mode 100644 index 0000000000..4ebb6cbdf0 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/cards_demo.dart @@ -0,0 +1,143 @@ +// Copyright 2016 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/widgets.dart'; + +class TravelDestination { + const TravelDestination({ this.assetName, this.title, this.description }); + + final String assetName; + final String title; + final List description; + + bool get isValid => assetName != null && title != null && description?.length == 3; +} + +final List destinations = [ + const TravelDestination( + assetName: 'packages/flutter_gallery_assets/top_10_australian_beaches.png', + title: 'Top 10 Australian beaches', + description: const [ + 'Number 10', + 'Whitehaven Beach', + 'Whitsunday Island, Whitsunday Islands' + ] + ), + const TravelDestination( + assetName: 'packages/flutter_gallery_assets/kangaroo_valley_safari.png', + title: 'Kangaroo Valley Safari', + description: const [ + '2031 Moss Vale Road', + 'Kangaroo Valley 2577', + 'New South Wales' + ] + ) +]; + +class TravelDestinationItem extends StatelessWidget { + TravelDestinationItem({ Key key, this.destination }) : super(key: key) { + assert(destination != null && destination.isValid); + } + + static final double height = 328.0; + final TravelDestination destination; + + @override + Widget build(BuildContext context) { + ThemeData theme = Theme.of(context); + TextStyle titleStyle = theme.textTheme.headline.copyWith(color: Colors.white); + TextStyle descriptionStyle = theme.textTheme.subhead; + + return new SizedBox( + height: height, + child: new Card( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // photo and title + new SizedBox( + height: 184.0, + child: new Stack( + children: [ + new Positioned( + left: 0.0, + top: 0.0, + bottom: 0.0, + right: 0.0, + child: new AssetImage( + name: destination.assetName, + fit: ImageFit.cover + ) + ), + new Positioned( + bottom: 16.0, + left: 16.0, + child: new Text(destination.title, style: titleStyle) + ) + ] + ) + ), + // description and share/expore buttons + new Flexible( + child: new Padding( + padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0), + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // three line description + new Text(destination.description[0], style: descriptionStyle), + new Text(destination.description[1], style: descriptionStyle), + new Text(destination.description[2], style: descriptionStyle), + ] + ) + ) + ), + // share, explore buttons + // TODO(abarth): The theme and the bar should be part of card. + new ButtonTheme.footer( + child: new ButtonBar( + alignment: MainAxisAlignment.start, + children: [ + new FlatButton( + child: new Text('SHARE'), + onPressed: () { /* do nothing */ } + ), + new FlatButton( + child: new Text('EXPLORE'), + onPressed: () { /* do nothing */ } + ), + ] + ) + ), + ] + ) + ) + ); + } +} + +class CardsDemo extends StatelessWidget { + static const String routeName = '/cards'; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Travel stream') + ), + body: new ScrollableList( + itemExtent: TravelDestinationItem.height, + padding: const EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), + children: destinations.map((TravelDestination destination) { + return new Container( + margin: const EdgeInsets.only(bottom: 8.0), + child: new TravelDestinationItem(destination: destination) + ); + }) + .toList() + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/chip_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/chip_demo.dart new file mode 100644 index 0000000000..08b2ae87f1 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/chip_demo.dart @@ -0,0 +1,54 @@ +// Copyright 2015 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'; + +class ChipDemo extends StatefulWidget { + static const String routeName = '/chip'; + + @override + _ChipDemoState createState() => new _ChipDemoState(); +} + +class _ChipDemoState extends State { + bool _showBananas = true; + + void _deleteBananas() { + setState(() { + _showBananas = false; + }); + } + + @override + Widget build(BuildContext context) { + List chips = [ + new Chip( + label: new Text('Apple') + ), + new Chip( + avatar: new CircleAvatar(child: new Text('B')), + label: new Text('Blueberry') + ), + ]; + + if (_showBananas) { + chips.add(new Chip( + label: new Text('Bananas'), + onDeleted: _deleteBananas + )); + } + + return new Scaffold( + appBar: new AppBar(title: new Text('Chips')), + body: new Block( + children: chips.map((Widget widget) { + return new Container( + height: 100.0, + child: new Center(child: widget) + ); + }).toList() + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/colors_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/colors_demo.dart new file mode 100644 index 0000000000..471b34913d --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/colors_demo.dart @@ -0,0 +1,138 @@ +// Copyright 2016 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/widgets.dart'; + +const double kColorItemHeight = 48.0; + +class ColorSwatch { + const ColorSwatch({ this.name, this.colors, this.accentColors, this.threshold: 900}); + + final String name; + final Map colors; + final Map accentColors; + final int threshold; // titles for indices > threshold are white, otherwise black + + bool get isValid => this.name != null && this.colors != null && threshold != null; +} + +const List colorSwatches = const [ + const ColorSwatch(name: 'RED', colors: Colors.red, accentColors: Colors.redAccent, threshold: 300), + const ColorSwatch(name: 'PINK', colors: Colors.pink, accentColors: Colors.pinkAccent, threshold: 200), + const ColorSwatch(name: 'PURPLE', colors: Colors.purple, accentColors: Colors.purpleAccent, threshold: 200), + const ColorSwatch(name: 'DEEP PURPLE', colors: Colors.deepPurple, accentColors: Colors.deepPurpleAccent, threshold: 200), + const ColorSwatch(name: 'INDIGO', colors: Colors.indigo, accentColors: Colors.indigoAccent, threshold: 200), + const ColorSwatch(name: 'BLUE', colors: Colors.blue, accentColors: Colors.blueAccent, threshold: 400), + const ColorSwatch(name: 'LIGHT BLUE', colors: Colors.lightBlue, accentColors: Colors.lightBlueAccent, threshold: 500), + const ColorSwatch(name: 'CYAN', colors: Colors.cyan, accentColors: Colors.cyanAccent, threshold: 600), + const ColorSwatch(name: 'TEAL', colors: Colors.teal, accentColors: Colors.tealAccent, threshold: 400), + const ColorSwatch(name: 'GREEN', colors: Colors.green, accentColors: Colors.greenAccent, threshold: 500), + const ColorSwatch(name: 'LIGHT GREEN', colors: Colors.lightGreen, accentColors: Colors.lightGreenAccent, threshold: 600), + const ColorSwatch(name: 'LIME', colors: Colors.lime, accentColors: Colors.limeAccent, threshold: 800), + const ColorSwatch(name: 'YELLOW', colors: Colors.yellow, accentColors: Colors.yellowAccent), + const ColorSwatch(name: 'AMBER', colors: Colors.amber, accentColors: Colors.amberAccent), + const ColorSwatch(name: 'ORANGE', colors: Colors.orange, accentColors: Colors.orangeAccent, threshold: 700), + const ColorSwatch(name: 'DEEP ORANGE', colors: Colors.deepOrange, accentColors: Colors.deepOrangeAccent, threshold: 400), + const ColorSwatch(name: 'BROWN', colors: Colors.brown, threshold: 200), + const ColorSwatch(name: 'GREY', colors: Colors.grey, threshold: 500), + const ColorSwatch(name: 'BLUE GREY', colors: Colors.blueGrey, threshold: 500) +]; + + +class ColorItem extends StatelessWidget { + ColorItem({ Key key, this.index, this.color, this.prefix: '' }) : super(key: key) { + assert(index != null); + assert(color != null); + assert(prefix != null); + } + + final int index; + final Color color; + final String prefix; + + String colorString() => "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; + + @override + Widget build(BuildContext context) { + return new Container( + height: kColorItemHeight, + padding: const EdgeInsets.symmetric(horizontal: 16.0), + decoration: new BoxDecoration(backgroundColor: color), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Text('$prefix$index'), + new Text(colorString()) + ] + ) + ); + } +} + +class ColorSwatchTabView extends StatelessWidget { + ColorSwatchTabView({ Key key, this.swatch }) : super(key: key) { + assert(swatch != null && swatch.isValid); + } + + final ColorSwatch swatch; + final TextStyle blackTextStyle = Typography.black.body1; + final TextStyle whiteTextStyle = Typography.white.body1; + + @override + Widget build(BuildContext context) { + List colorItems = swatch.colors.keys.map((int index) { + return new DefaultTextStyle( + style: index > swatch.threshold ? whiteTextStyle : blackTextStyle, + child: new ColorItem(index: index, color: swatch.colors[index]) + ); + }) + .toList(); + + if (swatch.accentColors != null) { + colorItems.addAll(swatch.accentColors.keys.map((int index) { + return new DefaultTextStyle( + style: index > swatch.threshold ? whiteTextStyle : blackTextStyle, + child: new ColorItem(index: index, color: swatch.accentColors[index], prefix: 'A') + ); + }) + .toList()); + } + + return new ScrollableList( + itemExtent: kColorItemHeight, + children: colorItems + ); + } +} + +class ColorsDemo extends StatelessWidget { + static const String routeName = '/colors'; + + @override + Widget build(BuildContext context) { + return new TabBarSelection( + values: colorSwatches, + child: new Scaffold( + appBar: new AppBar( + elevation: 0, + title: new Text('Colors'), + tabBar: new TabBar( + isScrollable: true, + labels: new Map.fromIterable(colorSwatches, value: (ColorSwatch swatch) { + return new TabLabel(text: swatch.name); + }) + ) + ), + body: new TabBarView( + children: colorSwatches.map((ColorSwatch swatch) { + return new ColorSwatchTabView(swatch: swatch); + }) + .toList() + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/data_table_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/data_table_demo.dart new file mode 100644 index 0000000000..2b6a0a325e --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/data_table_demo.dart @@ -0,0 +1,147 @@ +// Copyright 2016 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/rendering.dart'; + +class Desert { + Desert(this.name, this.calories, this.fat, this.carbs, this.protein, this.sodium, this.calcium, this.iron); + final String name; + final int calories; + final double fat; + final int carbs; + final double protein; + final int sodium; + final int calcium; + final int iron; + + bool selected = false; +} + +class DataTableDemo extends StatefulWidget { + static const String routeName = '/data-table'; + + @override + _DataTableDemoState createState() => new _DataTableDemoState(); +} + +class _DataTableDemoState extends State { + + int _sortColumnIndex; + bool _sortAscending = true; + + final List _deserts = [ + new Desert('Frozen yogurt', 159, 6.0, 24, 4.0, 87, 14, 1), + new Desert('Ice cream sandwich', 237, 9.0, 37, 4.3, 129, 8, 1), + new Desert('Eclair', 262, 16.0, 24, 6.0, 337, 6, 7), + new Desert('Cupcake', 305, 3.7, 67, 4.3, 413, 3, 8), + new Desert('Gingerbread', 356, 16.0, 49, 3.9, 327, 7, 16), + new Desert('Jelly bean', 375, 0.0, 94, 0.0, 50, 0, 0), + new Desert('Lollipop', 392, 0.2, 98, 0.0, 38, 0, 2), + new Desert('Honeycomb', 408, 3.2, 87, 6.5, 562, 0, 45), + new Desert('Donut', 452, 25.0, 51, 4.9, 326, 2, 22), + new Desert('KitKat', 518, 26.0, 65, 7.0, 54, 12, 6), + ]; + + void _sort/**/(Comparable getField(Desert d), int columnIndex, bool ascending) { + setState(() { + _deserts.sort((Desert a, Desert b) { + if (!ascending) { + final Desert c = a; + a = b; + b = c; + } + final Comparable aValue = getField(a); + final Comparable bValue = getField(b); + return Comparable.compare(aValue, bValue); + }); + _sortColumnIndex = columnIndex; + _sortAscending = ascending; + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Data tables')), + body: new Block( + children: [ + new Material( + child: new IntrinsicHeight( + child: new Block( + scrollDirection: Axis.horizontal, + children: [ + new DataTable( + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + columns: [ + new DataColumn( + label: new Text('Dessert (100g serving)'), + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.name, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Calories'), + tooltip: 'The total amount of food energy in the given serving size.', + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.calories, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Fat (g)'), + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.fat, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Carbs (g)'), + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.carbs, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Protein (g)'), + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.protein, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Sodium (mg)'), + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.sodium, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Calcium (%)'), + tooltip: 'The amount of calcium as a percentage of the recommended daily amount.', + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.calcium, columnIndex, ascending) + ), + new DataColumn( + label: new Text('Iron (%)'), + numeric: true, + onSort: (int columnIndex, bool ascending) => _sort/**/((Desert d) => d.iron, columnIndex, ascending) + ), + ], + rows: _deserts.map/**/((Desert desert) { + return new DataRow( + key: new ValueKey(desert), + selected: desert.selected, + onSelectChanged: (bool selected) { setState(() { desert.selected = selected; }); }, + cells: [ + new DataCell(new Text('${desert.name}')), + new DataCell(new Text('${desert.calories}')), + new DataCell(new Text('${desert.fat.toStringAsFixed(1)}')), + new DataCell(new Text('${desert.carbs}')), + new DataCell(new Text('${desert.protein.toStringAsFixed(1)}')), + new DataCell(new Text('${desert.sodium}')), + new DataCell(new Text('${desert.calcium}%')), + new DataCell(new Text('${desert.iron}%')), + ] + ); + }).toList(growable: false) + ) + ] + ) + ) + ) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/date_picker_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/date_picker_demo.dart new file mode 100644 index 0000000000..7244a2acd1 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/date_picker_demo.dart @@ -0,0 +1,52 @@ +// Copyright 2015 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 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class DatePickerDemo extends StatefulWidget { + static const String routeName = '/date-picker'; + + @override + _DatePickerDemoState createState() => new _DatePickerDemoState(); +} + +class _DatePickerDemoState extends State { + DateTime _selectedDate = new DateTime.now(); + + Future _handleSelectDate() async { + DateTime picked = await showDatePicker( + context: context, + initialDate: _selectedDate, + firstDate: new DateTime(2015, 8), + lastDate: new DateTime(2101) + ); + if (picked != _selectedDate) { + setState(() { + _selectedDate = picked; + }); + } + } + + @override + Widget build(BuildContext context) { + return + new Scaffold( + appBar: new AppBar(title: new Text('Date picker')), + body: new Column( + children: [ + new Text(new DateFormat.yMMMd().format(_selectedDate)), + new SizedBox(height: 20.0), + new RaisedButton( + onPressed: _handleSelectDate, + child: new Text('SELECT DATE') + ), + ], + mainAxisAlignment: MainAxisAlignment.center + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/dialog_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/dialog_demo.dart new file mode 100644 index 0000000000..f514a82ad0 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/dialog_demo.dart @@ -0,0 +1,203 @@ +// Copyright 2016 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/widgets.dart'; + +import 'full_screen_dialog_demo.dart'; + +enum DialogDemoAction { + cancel, + discard, + disagree, + agree, +} + +const String _alertWithoutTitleText = "Discard draft?"; + +const String _alertWithTitleText = + "Let Google help apps determine location. This means sending anyonmous location " + "data to Google, even when no apps are running."; + +class DialogDemoItem extends StatelessWidget { + DialogDemoItem({ Key key, this.icon, this.color, this.text, this.onPressed }) : super(key: key); + + final IconData icon; + final Color color; + final String text; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: onPressed, + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Icon( + size: 36.0, + icon: icon, + color: color + ), + new Padding( + padding: const EdgeInsets.only(left: 16.0), + child: new Text(text) + ) + ] + ) + ) + ); + } +} + +class DialogDemo extends StatefulWidget { + static const String routeName = '/dialog'; + + @override + DialogDemoState createState() => new DialogDemoState(); +} + +class DialogDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + + void showDemoDialog/**/({ BuildContext context, Dialog dialog }) { + showDialog/**/( + context: context, + child: dialog + ) + .then((dynamic/*=T*/ value) { // The value passed to Navigator.pop() or null. + if (value != null) { + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text('You selected: $value') + )); + } + }); + } + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle dialogTextStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); + + return new Scaffold( + key: _scaffoldKey, + appBar: new AppBar( + title: new Text('Dialogs') + ), + body: new Block( + padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0), + children: [ + new RaisedButton( + child: new Text('ALERT'), + onPressed: () { + showDemoDialog/**/( + context: context, + dialog: new Dialog( + content: new Text( + _alertWithoutTitleText, + style: dialogTextStyle + ), + actions: [ + new FlatButton( + child: new Text('CANCEL'), + onPressed: () { Navigator.pop(context, DialogDemoAction.cancel); } + ), + new FlatButton( + child: new Text('DISCARD'), + onPressed: () { Navigator.pop(context, DialogDemoAction.discard); } + ) + ] + ) + ); + } + ), + new RaisedButton( + child: new Text('ALERT WITH TITLE'), + onPressed: () { + showDemoDialog/**/( + context: context, + dialog: new Dialog( + title: new Text('Use Google\'s location service?'), + content: new Text( + _alertWithTitleText, + style: dialogTextStyle + ), + actions: [ + new FlatButton( + child: new Text('DISAGREE'), + onPressed: () { Navigator.pop(context, DialogDemoAction.disagree); } + ), + new FlatButton( + child: new Text('AGREE'), + onPressed: () { Navigator.pop(context, DialogDemoAction.agree); } + ) + ] + ) + ); + } + ), + new RaisedButton( + child: new Text('SIMPLE'), + onPressed: () { + showDemoDialog/**/( + context: context, + dialog: new Dialog( + title: new Text('Set backup account'), + content: new Column( + children: [ + new DialogDemoItem( + icon: Icons.account_circle, + color: theme.primaryColor, + text: 'username@gmail.com', + onPressed: () { Navigator.pop(context, 'username@gmail.com'); } + ), + new DialogDemoItem( + icon: Icons.account_circle, + color: theme.primaryColor, + text: 'user02@gmail.com', + onPressed: () { Navigator.pop(context, 'user02@gmail.com'); } + ), + new DialogDemoItem( + icon: Icons.add_circle, + text: 'add account', + color: theme.disabledColor + ) + ] + ) + ) + ); + } + ), + new RaisedButton( + child: new Text('CONFIRMATION'), + onPressed: () { + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 15, minute: 30) + ) + .then((TimeOfDay value) { // The value passed to Navigator.pop() or null. + if (value != null) { + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text('You selected: $value') + )); + } + }); + } + ), + new RaisedButton( + child: new Text('FULLSCREEN'), + onPressed: () { + Navigator.push(context, new MaterialPageRoute( + builder: (BuildContext context) => new FullScreenDialogDemo() + )); + } + ) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/drawing_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/drawing_demo.dart new file mode 100644 index 0000000000..9774d52f07 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/drawing_demo.dart @@ -0,0 +1,85 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:flutter_sprites/flutter_sprites.dart'; + +class DrawingDemo extends StatefulWidget { + static const String routeName = '/drawing'; + + @override + _DrawingDemoState createState() => new _DrawingDemoState(); +} + +class _DrawingDemoState extends State { + _LineDrawingNode _rootNode; + ImageMap _images; + + Future _loadAssets(AssetBundle bundle) async { + _images = new ImageMap(bundle); + await _images.load([ + 'packages/flutter_gallery_assets/fancylines.png' + ]); + } + + @override + void initState() { + super.initState(); + _loadAssets(DefaultAssetBundle.of(context)).then((_) { + setState(() { + _rootNode = new _LineDrawingNode(_images); + }); + }); + } + + @override + Widget build(BuildContext context) { + Widget body; + if (_rootNode == null) { + body = new Center( + child: new CircularProgressIndicator() + ); + } else { + body = new SpriteWidget(_rootNode, SpriteBoxTransformMode.nativePoints); + } + + return new Scaffold( + appBar: new AppBar( + title: new Text('Fancy lines') + ), + body: body + ); + } +} + +class _LineDrawingNode extends NodeWithSize { + _LineDrawingNode(this._images) : super(const Size(1024.0, 1024.0)) { + userInteractionEnabled = true; + } + + final ImageMap _images; + EffectLine _currentLine; + + @override + bool handleEvent(SpriteBoxEvent event) { + if (event.type == PointerDownEvent) { + _currentLine = new EffectLine( + texture: new Texture(_images['packages/flutter_gallery_assets/fancylines.png']), + colorSequence: new ColorSequence.fromStartAndEndColor(Colors.purple[500], Colors.purple[600]), + fadeAfterDelay: 3.0, + fadeDuration: 1.0 + ); + _currentLine.addPoint(event.boxPosition); + addChild(_currentLine); + } else if (event.type == PointerMoveEvent) { + _currentLine.addPoint(event.boxPosition); + } + + return true; + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/drop_down_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/drop_down_demo.dart new file mode 100644 index 0000000000..eeaa119434 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/drop_down_demo.dart @@ -0,0 +1,42 @@ +// Copyright 2015 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'; + +class DropDownDemo extends StatefulWidget { + static const String routeName = '/dropdown'; + + @override + _DropDownDemoState createState() => new _DropDownDemoState(); +} + +class _DropDownDemoState extends State { + String _value = "Free"; + + List> buildItems() { + return ["One", "Two", "Free", "Four"].map((String value) { + return new DropDownMenuItem(value: value, child: new Text(value)); + }) + .toList(); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Drop-down button')), + body: new Center( + child: new DropDownButton( + items: buildItems(), + value: _value, + onChanged: (String newValue) { + setState(() { + if (newValue != null) + _value = newValue; + }); + } + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/fitness_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/fitness_demo.dart new file mode 100644 index 0000000000..45cc3bac1f --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/fitness_demo.dart @@ -0,0 +1,589 @@ +// Copyright 2015 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 'dart:async'; +import 'dart:math' as math; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_sprites/flutter_sprites.dart'; + +ImageMap _images; +SpriteSheet _sprites; + +class FitnessDemo extends StatelessWidget { + FitnessDemo({ Key key }) : super(key: key); + + static const String routeName = '/fitness'; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Fitness') + ), + body: new _FitnessDemoContents() + ); + } +} + +class _FitnessDemoContents extends StatefulWidget { + _FitnessDemoContents({ Key key }) : super(key: key); + + @override + _FitnessDemoContentsState createState() => new _FitnessDemoContentsState(); +} + +class _FitnessDemoContentsState extends State<_FitnessDemoContents> { + + Future _loadAssets(AssetBundle bundle) async { + _images = new ImageMap(bundle); + await _images.load([ + 'packages/flutter_gallery_assets/jumpingjack.png', + ]); + + String json = await DefaultAssetBundle.of(context).loadString('packages/flutter_gallery_assets/jumpingjack.json'); + _sprites = new SpriteSheet(_images['packages/flutter_gallery_assets/jumpingjack.png'], json); + } + + @override + void initState() { + super.initState(); + + AssetBundle bundle = DefaultAssetBundle.of(context); + _loadAssets(bundle).then((_) { + setState(() { + _assetsLoaded = true; + workoutAnimation = new _WorkoutAnimationNode( + onPerformedJumpingJack: () { + setState(() { + _count += 1; + }); + }, + onSecondPassed: (int seconds) { + setState(() { + _time = seconds; + }); + } + ); + }); + }); + } + + bool _assetsLoaded = false; + int _count = 0; + int _time = 0; + int get kcal => (_count * 0.2).toInt(); + + _WorkoutAnimationNode workoutAnimation; + + @override + Widget build(BuildContext context) { + if (!_assetsLoaded) + return new Container(); + + Color buttonColor; + String buttonText; + VoidCallback onButtonPressed; + + if (workoutAnimation.workingOut) { + buttonColor = Colors.red[500]; + buttonText = "STOP WORKOUT"; + onButtonPressed = endWorkout; + } else { + buttonColor = Theme.of(context).primaryColor; + buttonText = "START WORKOUT"; + onButtonPressed = startWorkout; + } + + return new Material( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Flexible( + child: new Container( + decoration: new BoxDecoration(backgroundColor: Colors.grey[800]), + child: new SpriteWidget(workoutAnimation, SpriteBoxTransformMode.scaleToFit) + ) + ), + new Padding( + padding: new EdgeInsets.only(top: 20.0), + child: new Text('JUMPING JACKS', style: Theme.of(context).textTheme.title) + ), + new Padding( + padding: new EdgeInsets.only(top: 20.0, bottom: 20.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _createInfoPanelCell(Icons.accessibility, '$_count', 'COUNT'), + _createInfoPanelCell(Icons.timer, _formatSeconds(_time), 'TIME'), + _createInfoPanelCell(Icons.flash_on, '$kcal', 'KCAL') + ] + ) + ), + new Padding( + padding: new EdgeInsets.only(bottom: 16.0), + child: new SizedBox( + width: 300.0, + height: 72.0, + child: new RaisedButton ( + onPressed: onButtonPressed, + color: buttonColor, + child: new Text( + buttonText, + style: new TextStyle(color: Colors.white, fontSize: 20.0) + ) + ) + ) + ) + ] + ) + ); + } + + Widget _createInfoPanelCell(IconData icon, String value, String description) { + Color color; + if (workoutAnimation.workingOut) + color = Colors.black87; + else + color = Theme.of(context).disabledColor; + + return new Container( + width: 100.0, + child: new Center( + child: new Column( + children: [ + new Icon(icon: icon, size: 48.0, color: color), + new Text(value, style: new TextStyle(fontSize: 24.0, color: color)), + new Text(description, style: new TextStyle(color: color)) + ] + ) + ) + ); + } + + String _formatSeconds(int seconds) { + int minutes = seconds ~/ 60; + String secondsStr = "${seconds % 60}".padLeft(2, "0"); + return "$minutes:$secondsStr"; + } + + void startWorkout() { + setState(() { + _count = 0; + _time = 0; + workoutAnimation.start(); + }); + } + + void endWorkout() { + setState(() { + workoutAnimation.stop(); + + if (_count >= 3) { + showDialog( + context: context, + child: new Stack(children: [ + new _Fireworks(), + new Dialog( + title: new Text('Awesome workout'), + content: new Text('You have completed $_count jumping jacks. Good going!'), + actions: [ + new FlatButton( + child: new Text('SWEET'), + onPressed: () { Navigator.pop(context); } + ) + ] + ) + ]) + ); + } + }); + } +} + +typedef void _SecondPassedCallback(int seconds); + +class _WorkoutAnimationNode extends NodeWithSize { + _WorkoutAnimationNode({ + this.onPerformedJumpingJack, + this.onSecondPassed + }) : super(const Size(1024.0, 1024.0)) { + reset(); + + _progress = new _ProgressCircle(const Size(800.0, 800.0)); + _progress.pivot = const Point(0.5, 0.5); + _progress.position = const Point(512.0, 512.0); + addChild(_progress); + + _jumpingJack = new _JumpingJack((){ + onPerformedJumpingJack(); + }); + _jumpingJack.scale = 0.5; + _jumpingJack.position = const Point(512.0, 550.0); + addChild(_jumpingJack); + } + + final VoidCallback onPerformedJumpingJack; + final _SecondPassedCallback onSecondPassed; + + int seconds; + + bool workingOut; + + static const int _kTargetMillis = 1000 * 30; + int _startTimeMillis; + _ProgressCircle _progress; + _JumpingJack _jumpingJack; + + void reset() { + seconds = 0; + workingOut = false; + } + + void start() { + reset(); + _startTimeMillis = new DateTime.now().millisecondsSinceEpoch; + workingOut = true; + _jumpingJack.animateJumping(); + } + + void stop() { + workingOut = false; + _jumpingJack.neutralPose(); + } + + @override + void update(double dt) { + if (workingOut) { + int millis = new DateTime.now().millisecondsSinceEpoch - _startTimeMillis; + int newSeconds = (millis) ~/ 1000; + if (newSeconds != seconds) { + seconds = newSeconds; + onSecondPassed(seconds); + } + + _progress.value = millis / _kTargetMillis; + } else { + _progress.value = 0.0; + } + } +} + +class _ProgressCircle extends NodeWithSize { + _ProgressCircle(Size size, [this.value = 0.0]) : super(size); + + static const double _kTwoPI = math.PI * 2.0; + static const double _kEpsilon = .0000001; + static const double _kSweep = _kTwoPI - _kEpsilon; + + double value; + + @override + void paint(Canvas canvas) { + applyTransformForPivot(canvas); + + Paint circlePaint = new Paint() + ..color = Colors.white30 + ..strokeWidth = 24.0 + ..style = PaintingStyle.stroke; + + canvas.drawCircle( + new Point(size.width / 2.0, size.height / 2.0), + size.width / 2.0, + circlePaint + ); + + Paint pathPaint = new Paint() + ..color = Colors.purple[500] + ..strokeWidth = 25.0 + ..style = PaintingStyle.stroke; + + double angle = value.clamp(0.0, 1.0) * _kSweep; + Path path = new Path() + ..arcTo(Point.origin & size, -math.PI / 2.0, angle, false); + canvas.drawPath(path, pathPaint); + } +} + +class _JumpingJack extends Node { + _JumpingJack(VoidCallback onPerformedJumpingJack) { + left = new _JumpingJackSide(false, onPerformedJumpingJack); + right = new _JumpingJackSide(true, null); + addChild(left); + addChild(right); + } + + void animateJumping() { + left.animateJumping(); + right.animateJumping(); + } + + void neutralPose() { + left.neutralPosition(true); + right.neutralPosition(true); + } + + _JumpingJackSide left; + _JumpingJackSide right; +} + +class _JumpingJackSide extends Node { + _JumpingJackSide(bool right, this.onPerformedJumpingJack) { + // Torso and head + torso = _createPart('torso.png', const Point(512.0, 512.0)); + addChild(torso); + + head = _createPart('head.png', const Point(512.0, 160.0)); + torso.addChild(head); + + if (right) { + torso.opacity = 0.0; + head.opacity = 0.0; + torso.scaleX = -1.0; + } + + // Left side movable parts + upperArm = _createPart('upper-arm.png', const Point(445.0, 220.0)); + torso.addChild(upperArm); + lowerArm = _createPart('lower-arm.png', const Point(306.0, 200.0)); + upperArm.addChild(lowerArm); + hand = _createPart('hand.png', const Point(215.0, 127.0)); + lowerArm.addChild(hand); + upperLeg = _createPart('upper-leg.png', const Point(467.0, 492.0)); + torso.addChild(upperLeg); + lowerLeg = _createPart('lower-leg.png', const Point(404.0, 660.0)); + upperLeg.addChild(lowerLeg); + foot = _createPart('foot.png', const Point(380.0, 835.0)); + lowerLeg.addChild(foot); + + torso.setPivotAndPosition(Point.origin); + + neutralPosition(false); + } + + _JumpingJackPart torso; + _JumpingJackPart head; + _JumpingJackPart upperArm; + _JumpingJackPart lowerArm; + _JumpingJackPart hand; + _JumpingJackPart lowerLeg; + _JumpingJackPart upperLeg; + _JumpingJackPart foot; + + final VoidCallback onPerformedJumpingJack; + + _JumpingJackPart _createPart(String textureName, Point pivotPosition) { + return new _JumpingJackPart(_sprites[textureName], pivotPosition); + } + + void animateJumping() { + actions.stopAll(); + actions.run(new ActionSequence([ + _createPoseAction(null, 0, 0.5), + new ActionCallFunction(_animateJumpingLoop) + ])); + } + + void _animateJumpingLoop() { + actions.run(new ActionRepeatForever( + new ActionSequence([ + _createPoseAction(0, 1, 0.30), + _createPoseAction(1, 2, 0.30), + _createPoseAction(2, 1, 0.30), + _createPoseAction(1, 0, 0.30), + new ActionCallFunction(() { + if (onPerformedJumpingJack != null) + onPerformedJumpingJack(); + }) + ]) + )); + } + + void neutralPosition(bool animate) { + actions.stopAll(); + if (animate) { + actions.run(_createPoseAction(null, 1, 0.5)); + } else { + List d = _dataForPose(1); + upperArm.rotation = d[0]; + lowerArm.rotation = d[1]; + hand.rotation = d[2]; + upperLeg.rotation = d[3]; + lowerLeg.rotation = d[4]; + foot.rotation = d[5]; + torso.position = new Point(0.0, d[6]); + } + } + + ActionInterval _createPoseAction(int startPose, int endPose, double duration) { + List d0 = _dataForPose(startPose); + List d1 = _dataForPose(endPose); + + List tweens = [ + _tweenRotation(upperArm, d0[0], d1[0], duration), + _tweenRotation(lowerArm, d0[1], d1[1], duration), + _tweenRotation(hand, d0[2], d1[2], duration), + _tweenRotation(upperLeg, d0[3], d1[3], duration), + _tweenRotation(lowerLeg, d0[4], d1[4], duration), + _tweenRotation(foot, d0[5], d1[5], duration), + new ActionTween( + (Point a) => torso.position = a, + new Point(0.0, d0[6]), + new Point(0.0, d1[6]), + duration + ) + ]; + + return new ActionGroup(tweens); + } + + ActionTween _tweenRotation(_JumpingJackPart part, double r0, double r1, double duration) { + return new ActionTween( + (double a) => part.rotation = a, + r0, + r1, + duration + ); + } + + List _dataForPose(int pose) { + if (pose == null) + return _dataForCurrentPose(); + + if (pose == 0) { + return [ + -80.0, // Upper arm rotation + -30.0, // Lower arm rotation + -10.0, // Hand rotation + -15.0, // Upper leg rotation + 5.0, // Lower leg rotation + 15.0, // Foot rotation + 0.0 // Torso y offset + ]; + } else if (pose == 1) { + return [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -70.0 + ]; + } else { + return [ + 40.0, + 30.0, + 10.0, + 20.0, + -20.0, + 15.0, + 40.0 + ]; + } + } + + List _dataForCurrentPose() { + return [ + upperArm.rotation, + lowerArm.rotation, + hand.rotation, + upperLeg.rotation, + lowerLeg.rotation, + foot.rotation, + torso.position.y + ]; + } +} + +class _JumpingJackPart extends Sprite { + _JumpingJackPart(Texture texture, this.pivotPosition) : super(texture); + final Point pivotPosition; + + void setPivotAndPosition(Point newPosition) { + pivot = new Point(pivotPosition.x / 1024.0, pivotPosition.y / 1024.0); + position = newPosition; + + for (Node child in children) { + _JumpingJackPart subPart = child; + subPart.setPivotAndPosition( + new Point( + subPart.pivotPosition.x - pivotPosition.x, + subPart.pivotPosition.y - pivotPosition.y + ) + ); + } + } +} + +class _Fireworks extends StatefulWidget { + _Fireworks({ Key key }) : super(key: key); + + @override + _FireworksState createState() => new _FireworksState(); +} + +class _FireworksState extends State<_Fireworks> { + @override + void initState() { + super.initState(); + fireworks = new _FireworksNode(); + } + + _FireworksNode fireworks; + + @override + Widget build(BuildContext context) { + return new SpriteWidget(fireworks); + } +} + +class _FireworksNode extends NodeWithSize { + _FireworksNode() : super(const Size(1024.0, 1024.0)); + double _countDown = 0.0; + + @override + void update(double dt) { + if (_countDown <= 0.0) { + _addExplosion(); + _countDown = randomDouble(); + } + + _countDown -= dt; + } + + Color _randomExplosionColor() { + double rand = randomDouble(); + if (rand < 0.25) + return Colors.pink[200]; + else if (rand < 0.5) + return Colors.lightBlue[200]; + else if (rand < 0.75) + return Colors.purple[200]; + else + return Colors.cyan[200]; + } + + void _addExplosion() { + Color startColor = _randomExplosionColor(); + Color endColor = startColor.withAlpha(0); + + ParticleSystem system = new ParticleSystem( + _sprites['particle-0.png'], + numParticlesToEmit: 100, + emissionRate: 1000.0, + rotateToMovement: true, + startRotation: 90.0, + endRotation: 90.0, + speed: 100.0, + speedVar: 50.0, + startSize: 1.0, + startSizeVar: 0.5, + gravity: const Offset(0.0, 30.0), + colorSequence: new ColorSequence.fromStartAndEndColor(startColor, endColor) + ); + system.position = new Point(randomDouble() * 1024.0, randomDouble() * 1024.0); + addChild(system); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/flexible_space_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/flexible_space_demo.dart new file mode 100644 index 0000000000..d63b082144 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/flexible_space_demo.dart @@ -0,0 +1,204 @@ +// Copyright 2015 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/widgets.dart'; + +class _ContactCategory extends StatelessWidget { + _ContactCategory({ Key key, this.icon, this.children }) : super(key: key); + + final IconData icon; + final List children; + + @override + Widget build(BuildContext context) { + return new Container( + padding: const EdgeInsets.symmetric(vertical: 16.0), + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: Theme.of(context).dividerColor)) + ), + child: new DefaultTextStyle( + style: Theme.of(context).textTheme.subhead, + child: new Row( + children: [ + new SizedBox( + width: 72.0, + child: new Icon(icon: icon, color: Theme.of(context).primaryColor) + ), + new Flexible(child: new Column(children: children)) + ] + ) + ) + ); + } +} + +class _ContactItem extends StatelessWidget { + _ContactItem({ Key key, this.icon, this.lines }) : super(key: key) { + assert(lines.length > 1); + } + + final IconData icon; + final List lines; + + @override + Widget build(BuildContext context) { + List columnChildren = lines.sublist(0, lines.length - 1).map((String line) => new Text(line)).toList(); + columnChildren.add(new Text(lines.last, style: Theme.of(context).textTheme.caption)); + + List rowChildren = [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: columnChildren + ) + ]; + if (icon != null) { + rowChildren.add(new SizedBox( + width: 72.0, + child: new Icon(icon: icon, color: Theme.of(context).disabledColor) + )); + } + return new Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: rowChildren + ) + ); + } +} + +class FlexibleSpaceDemo extends StatefulWidget { + static const String routeName = '/flexible-space'; + + @override + FlexibleSpaceDemoState createState() => new FlexibleSpaceDemoState(); +} + +class FlexibleSpaceDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + final double _appBarHeight = 256.0; + AppBarBehavior _appBarBehavior = AppBarBehavior.scroll; + + @override + Widget build(BuildContext context) { + final double statusBarHeight = MediaQuery.of(context).padding.top; + return new Theme( + data: new ThemeData( + brightness: ThemeBrightness.light, + primarySwatch: Colors.indigo + ), + child: new Scaffold( + key: _scaffoldKey, + appBarBehavior: _appBarBehavior, + appBar: new AppBar( + expandedHeight: _appBarHeight, + actions: [ + new IconButton( + icon: Icons.create, + tooltip: 'Search', + onPressed: () { + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text('Not supported.') + )); + } + ), + new PopupMenuButton( + onSelected: (AppBarBehavior value) { + setState(() { + _appBarBehavior = value; + }); + }, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: AppBarBehavior.scroll, + child: new Text('Toolbar scrolls away') + ), + new PopupMenuItem( + value: AppBarBehavior.under, + child: new Text('Toolbar stays put') + ) + ] + ) + ], + flexibleSpace: new FlexibleSpaceBar( + title : new Text('Ali Connors'), + background: new AssetImage( + name: 'packages/flutter_gallery_assets/ali_connors.png', + fit: ImageFit.cover, + height: _appBarHeight + ) + ) + ), + body: new Block( + padding: new EdgeInsets.only(top: _appBarHeight + statusBarHeight), + children: [ + new _ContactCategory( + icon: Icons.call, + children: [ + new _ContactItem( + icon: Icons.message, + lines: [ + '(650) 555-1234', + 'Mobile' + ] + ), + new _ContactItem( + icon: Icons.message, + lines: [ + '(323) 555-6789', + 'Work' + ] + ) + ] + ), + new _ContactCategory( + icon: Icons.email, + children: [ + new _ContactItem( + lines: [ + 'ali_connors@example.com', + 'Personal' + ] + ), + new _ContactItem( + lines: [ + 'aliconnors@example.com', + 'Work' + ] + ) + ] + ), + new _ContactCategory( + icon: Icons.location_on, + children: [ + new _ContactItem( + lines: [ + '2000 Main Street', + 'San Francisco, CA', + 'Home' + ] + ), + new _ContactItem( + lines: [ + '1600 Amphitheater Parkway', + 'Mountain View, CA', + 'Work' + ] + ), + new _ContactItem( + lines: [ + '126 Severyns Ave', + 'Mountain View, CA', + 'Jet Travel' + ] + ) + ] + ) + ] + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/full_screen_dialog_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/full_screen_dialog_demo.dart new file mode 100644 index 0000000000..ecb7889814 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/full_screen_dialog_demo.dart @@ -0,0 +1,246 @@ +// Copyright 2016 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:intl/intl.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// This demo is based on +// https://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs + +enum DismissDialogAction { + cancel, + discard, + save, +} + +class DateTimeItem extends StatelessWidget { + DateTimeItem({ Key key, DateTime dateTime, this.onChanged }) + : date = new DateTime(dateTime.year, dateTime.month, dateTime.day), + time = new TimeOfDay(hour: dateTime.hour, minute: dateTime.minute), + super(key: key) { + assert(onChanged != null); + } + + final DateTime date; + final TimeOfDay time; + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + + return new DefaultTextStyle( + style: theme.textTheme.subhead, + child: new Row( + children: [ + new Flexible( + child: new Container( + padding: const EdgeInsets.symmetric(vertical: 8.0), + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new InkWell( + onTap: () { + showDatePicker( + context: context, + initialDate: date, + firstDate: date.subtract(const Duration(days: 30)), + lastDate: date.add(const Duration(days: 30)) + ) + .then((DateTime value) { + onChanged(new DateTime(value.year, value.month, value.day, time.hour, time.minute)); + }); + }, + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Text(new DateFormat('EEE, MMM d yyyy').format(date)), + new Icon(icon: Icons.arrow_drop_down, color: Colors.black54), + ] + ) + ) + ) + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new InkWell( + onTap: () { + showTimePicker( + context: context, + initialTime: time + ) + .then((TimeOfDay value) { + onChanged(new DateTime(date.year, date.month, date.day, value.hour, value.minute)); + }); + }, + child: new Row( + children: [ + new Text('$time'), + new Icon(icon: Icons.arrow_drop_down, color: Colors.black54), + ] + ) + ) + ) + ] + ) + ); + } +} + +class FullScreenDialogDemo extends StatefulWidget { + @override + FullScreenDialogDemoState createState() => new FullScreenDialogDemoState(); +} + +class FullScreenDialogDemoState extends State { + DateTime _fromDateTime = new DateTime.now(); + DateTime _toDateTime = new DateTime.now(); + bool _allDayValue = false; + bool _saveNeeded = false; + + void handleDismissButton(BuildContext context) { + if (!_saveNeeded) { + Navigator.pop(context, null); + return; + } + + final ThemeData theme = Theme.of(context); + final TextStyle dialogTextStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); + + showDialog( + context: context, + child: new Dialog( + content: new Text( + 'Discard new event?', + style: dialogTextStyle + ), + actions: [ + new FlatButton( + child: new Text('CANCEL'), + onPressed: () { Navigator.pop(context, DismissDialogAction.cancel); } + ), + new FlatButton( + child: new Text('DISCARD'), + onPressed: () { + Navigator.openTransaction(context, (NavigatorTransaction transaction) { + transaction.pop(DismissDialogAction.discard); // pop the cancel/discard dialog + transaction.pop(null); // pop this route + }); + } + ) + ] + ) + ); + } + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + + return new Scaffold( + appBar: new AppBar( + leading: new IconButton( + icon: Icons.clear, + onPressed: () { handleDismissButton(context); } + ), + title: new Text('New event'), + actions: [ + new FlatButton( + child: new Text('SAVE', style: theme.textTheme.body1.copyWith(color: Colors.white)), + onPressed: () { + Navigator.pop(context, DismissDialogAction.save); + } + ) + ] + ), + body: new Block( + padding: const EdgeInsets.all(16.0), + children: [ + new Container( + padding: const EdgeInsets.symmetric(vertical: 8.0), + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new Align( + alignment: FractionalOffset.bottomLeft, + child: new Text('Event name', style: theme.textTheme.display2) + ) + ), + new Container( + padding: const EdgeInsets.symmetric(vertical: 8.0), + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new Align( + alignment: FractionalOffset.bottomLeft, + child: new Text('Location', style: theme.textTheme.title.copyWith(color: Colors.black54)) + ) + ), + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text('From', style: theme.textTheme.caption), + new DateTimeItem( + dateTime: _fromDateTime, + onChanged: (DateTime value) { + setState(() { + _fromDateTime = value; + _saveNeeded = true; + }); + } + ) + ] + ), + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text('To', style: theme.textTheme.caption), + new DateTimeItem( + dateTime: _toDateTime, + onChanged: (DateTime value) { + setState(() { + _toDateTime = value; + _saveNeeded = true; + }); + } + ) + ] + ), + new Container( + decoration: new BoxDecoration( + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new Row( + children: [ + new Checkbox( + value: _allDayValue, + onChanged: (bool value) { + setState(() { + _allDayValue = value; + _saveNeeded = true; + }); + } + ), + new Text('All-day') + ] + ) + ) + ] + .map((Widget child) { + return new Container( + padding: const EdgeInsets.symmetric(vertical: 8.0), + height: 96.0, + child: child + ); + }) + .toList() + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/grid_list_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/grid_list_demo.dart new file mode 100644 index 0000000000..129be0913c --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/grid_list_demo.dart @@ -0,0 +1,283 @@ +// Copyright 2016 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 'dart:collection'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../gallery/demo.dart'; + +const String _kExampleCode = 'gridlists'; + +enum GridDemoTileStyle { + imageOnly, + oneLine, + twoLine +} + +class Photo { + Photo({ this.assetName, this.title, this.caption, this.isFavorite: false }); + + final String assetName; + final String title; + final String caption; + + bool isFavorite; + + bool get isValid => assetName != null && title != null && caption != null && isFavorite != null; +} + +const String photoHeroTag = 'Photo'; + +typedef void PhotoFavoriteCallback(Photo photo); + +class GridDemoPhotoItem extends StatelessWidget { + GridDemoPhotoItem({ + Key key, + this.photo, + this.tileStyle, + this.onPressedFavorite + }) : super(key: key) { + assert(photo != null && photo.isValid); + assert(tileStyle != null); + assert(onPressedFavorite != null); + } + + final Photo photo; + final GridDemoTileStyle tileStyle; + final PhotoFavoriteCallback onPressedFavorite; + + void showPhoto(BuildContext context) { + Key photoKey = new Key(photo.assetName); + Set mostValuableKeys = new HashSet(); + mostValuableKeys.add(photoKey); + + Navigator.push(context, new MaterialPageRoute( + settings: new RouteSettings( + mostValuableKeys: mostValuableKeys + ), + builder: (BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(photo.title) + ), + body: new Material( + child: new Hero( + tag: photoHeroTag, + child: new AssetImage( + name: photo.assetName, + fit: ImageFit.cover + ) + ) + ) + ); + } + )); + } + + @override + Widget build(BuildContext context) { + final Widget image = new GestureDetector( + onTap: () { showPhoto(context); }, + child: new Hero( + key: new Key(photo.assetName), + tag: photoHeroTag, + child: new AssetImage( + name: photo.assetName, + fit: ImageFit.cover + ) + ) + ); + + IconData icon = photo.isFavorite ? Icons.star : Icons.star_border; + + switch(tileStyle) { + case GridDemoTileStyle.imageOnly: + return image; + + case GridDemoTileStyle.oneLine: + return new GridTile( + header: new GridTileBar( + backgroundColor: Colors.black45, + leading: new IconButton( + icon: icon, + color: Colors.white, + onPressed: () { onPressedFavorite(photo); } + ), + title: new Text(photo.title) + ), + child: image + ); + + case GridDemoTileStyle.twoLine: + return new GridTile( + footer: new GridTileBar( + backgroundColor: Colors.black45, + title: new Text(photo.title), + subtitle: new Text(photo.caption), + trailing: new IconButton( + icon: icon, + color: Colors.white, + onPressed: () { onPressedFavorite(photo); } + ) + ), + child: image + ); + } + } +} + +class GridListDemo extends StatefulWidget { + GridListDemo({ Key key }) : super(key: key); + + static const String routeName = '/grid-list'; + + @override + GridListDemoState createState() => new GridListDemoState(); +} + +class GridListDemoState extends State { + GridDemoTileStyle tileStyle = GridDemoTileStyle.twoLine; + + List photos = [ + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_0.jpg', + title: 'Philippines', + caption: 'Batad rice terraces' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_1.jpg', + title: 'Italy', + caption: 'Ceresole Reale' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_2.jpg', + title: 'Somewhere', + caption: 'Beautiful mountains' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_3.jpg', + title: 'A place', + caption: 'Beautiful hills' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_4.jpg', + title: 'New Zealand', + caption: 'View from the van' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_5.jpg', + title: 'Autumn', + caption: 'The golden season' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_6.jpg', + title: 'Germany', + caption: 'Englischer Garten' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_7.jpg', + title: 'A country', + caption: 'Grass fields' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_8.jpg', + title: 'Mountain country', + caption: 'River forest' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_9.jpg', + title: 'Alpine place', + caption: 'Green hills' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_10.jpg', + title: 'Desert land', + caption: 'Blue skies' + ), + new Photo( + assetName: 'packages/flutter_gallery_assets/landscape_11.jpg', + title: 'Narnia', + caption: 'Rocks and rivers' + ), + ]; + + void showTileStyleMenu(BuildContext context) { + final List> items = >[ + new PopupMenuItem( + value: GridDemoTileStyle.imageOnly, + child: new Text('Image only') + ), + new PopupMenuItem( + value: GridDemoTileStyle.oneLine, + child: new Text('One line') + ), + new PopupMenuItem( + value: GridDemoTileStyle.twoLine, + child: new Text('Two line') + ) + ]; + + final EdgeInsets padding = MediaQuery.of(context).padding; + final RelativeRect position = new RelativeRect.fromLTRB( + 0.0, padding.top + 16.0, padding.right + 16.0, 0.0 + ); + + showMenu(context: context, position: position, items: items).then((GridDemoTileStyle value) { + setState(() { + tileStyle = value; + }); + }); + } + + // When the ScrollableGrid first appears we want the last row to only be + // partially visible, to help the user recognize that the grid is scrollable. + // The GridListDemoGridDelegate's tileHeightFactor is used for this. + @override + Widget build(BuildContext context) { + final Orientation orientation = MediaQuery.of(context).orientation; + return new Scaffold( + appBar: new AppBar( + title: new Text('Grid list'), + actions: [ + new IconButton( + icon: Icons.more_vert, + onPressed: () { showTileStyleMenu(context); }, + tooltip: 'Show menu' + ) + ] + ), + body: new Column( + children: [ + new Flexible( + child: new ScrollableGrid( + delegate: new FixedColumnCountGridDelegate( + columnCount: (orientation == Orientation.portrait) ? 2 : 3, + rowSpacing: 4.0, + columnSpacing: 4.0, + padding: const EdgeInsets.all(4.0), + tileAspectRatio: (orientation == Orientation.portrait) ? 1.0 : 1.3 + ), + children: photos.map((Photo photo) { + return new GridDemoPhotoItem( + photo: photo, + tileStyle: tileStyle, + onPressedFavorite: (Photo photo) { + setState(() { + photo.isFavorite = !photo.isFavorite; + }); + } + ); + }) + ) + ), + new DemoBottomBar( + exampleCodeTag: _kExampleCode + ) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/icons_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/icons_demo.dart new file mode 100644 index 0000000000..b83ef8c542 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/icons_demo.dart @@ -0,0 +1,162 @@ +// Copyright 2016 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'; + +class IconsDemo extends StatefulWidget { + static const String routeName = '/icons'; + + @override + IconsDemoState createState() => new IconsDemoState(); +} + +class IconsDemoState extends State { + static final List> iconColorSwatches = >[ + Colors.red, + Colors.pink, + Colors.purple, + Colors.deepPurple, + Colors.indigo, + Colors.blue, + Colors.lightBlue, + Colors.cyan, + Colors.teal, + Colors.green, + Colors.lightGreen, + Colors.lime, + Colors.yellow, + Colors.amber, + Colors.orange, + Colors.deepOrange, + Colors.brown, + Colors.grey, + Colors.blueGrey + ]; + + int iconColorIndex = 2; + double iconOpacity = 1.0; + + Color get iconColor => iconColorSwatches[iconColorIndex][400]; + + void handleIconButtonPress() { + setState(() { + iconColorIndex = (iconColorIndex + 1) % iconColorSwatches.length; + }); + } + + Widget buildIconButton(double size, IconData icon, bool enabled) { + return new IconButton( + size: size, + icon: icon, + color: iconColor, + tooltip: "${enabled ? 'enabled' : 'disabled'} icon button", + onPressed: enabled ? handleIconButtonPress : null + ); + } + + Widget buildSizeLabel(int size, TextStyle style) { + return new SizedBox( + height: size.toDouble() + 16.0, // to match an IconButton's padded height + child: new Center( + child: new Text('$size', style: style) + ) + ); + } + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle textStyle = theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); + + return new Scaffold( + appBar: new AppBar( + title: new Text('Icons') + ), + body: new IconTheme( + data: new IconThemeData(opacity: iconOpacity), + child: new Padding( + padding: const EdgeInsets.all(24.0), + child: new Column( + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Flexible( + flex: 0, + child: new Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Text('Size', style: textStyle), + buildSizeLabel(18, textStyle), + buildSizeLabel(24, textStyle), + buildSizeLabel(36, textStyle), + buildSizeLabel(48, textStyle) + ] + ) + ), + new Flexible( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Text('Enabled', style: textStyle), + buildIconButton(18.0, Icons.face, true), + buildIconButton(24.0, Icons.alarm, true), + buildIconButton(36.0, Icons.home, true), + buildIconButton(48.0, Icons.android, true) + ] + ) + ), + new Flexible( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Text('Disabled', style: textStyle), + buildIconButton(18.0, Icons.face, false), + buildIconButton(24.0, Icons.alarm, false), + buildIconButton(36.0, Icons.home, false), + buildIconButton(48.0, Icons.android, false) + ] + ) + ) + ] + ), + new Flexible( + child: new Center( + child: new IconTheme( + data: new IconThemeData(opacity: 1.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Icon( + icon: Icons.brightness_7, + color: iconColor.withAlpha(0x33) // 0.2 * 255 = 0x33 + ), + new Slider( + value: iconOpacity, + min: 0.2, + max: 1.0, + activeColor: iconColor, + onChanged: (double newValue) { + setState(() { + iconOpacity = newValue; + }); + } + ), + new Icon( + icon: Icons.brightness_7, + color: iconColor.withAlpha(0xFF) + ), + ] + ) + ) + ) + ) + ] + ) + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/leave_behind_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/leave_behind_demo.dart new file mode 100644 index 0000000000..9e4ed1880f --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/leave_behind_demo.dart @@ -0,0 +1,170 @@ +// Copyright 2016 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:collection/collection.dart' show lowerBound; + +import 'package:flutter/material.dart'; + +enum LeaveBehindDemoAction { + reset, + horizontalSwipe, + leftSwipe, + rightSwipe +} + +class LeaveBehindItem implements Comparable { + LeaveBehindItem({ this.index, this.name, this.subject, this.body }); + + LeaveBehindItem.from(LeaveBehindItem item) + : index = item.index, name = item.name, subject = item.subject, body = item.body; + + final int index; + final String name; + final String subject; + final String body; + + @override + int compareTo(LeaveBehindItem other) => index.compareTo(other.index); +} + +class LeaveBehindDemo extends StatefulWidget { + LeaveBehindDemo({ Key key }) : super(key: key); + + static const String routeName = '/leave-behind'; + + @override + LeaveBehindDemoState createState() => new LeaveBehindDemoState(); +} + +class LeaveBehindDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + DismissDirection _dismissDirection = DismissDirection.horizontal; + List leaveBehindItems; + + void initListItems() { + leaveBehindItems = new List.generate(16, (int index) { + return new LeaveBehindItem( + index: index, + name: 'Item $index Sender', + subject: 'Subject: $index', + body: "[$index] first line of the message's body..." + ); + }); + } + + @override + void initState() { + super.initState(); + initListItems(); + } + + void handleDemoAction(LeaveBehindDemoAction action) { + switch(action) { + case LeaveBehindDemoAction.reset: + initListItems(); + break; + case LeaveBehindDemoAction.horizontalSwipe: + _dismissDirection = DismissDirection.horizontal; + break; + case LeaveBehindDemoAction.leftSwipe: + _dismissDirection = DismissDirection.endToStart; + break; + case LeaveBehindDemoAction.rightSwipe: + _dismissDirection = DismissDirection.startToEnd; + break; + } + } + + void handleUndo(LeaveBehindItem item) { + int insertionIndex = lowerBound(leaveBehindItems, item); + setState(() { + leaveBehindItems.insert(insertionIndex, item); + }); + } + + Widget buildItem(LeaveBehindItem item) { + final ThemeData theme = Theme.of(context); + return new Dismissable( + key: new ObjectKey(item), + direction: _dismissDirection, + onDismissed: (DismissDirection direction) { + setState(() { + leaveBehindItems.remove(item); + }); + final String action = (direction == DismissDirection.endToStart) ? 'archived' : 'deleted'; + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text('You $action item ${item.index}'), + action: new SnackBarAction( + label: 'UNDO', + onPressed: () { handleUndo(item); } + ) + )); + }, + background: new Container( + decoration: new BoxDecoration(backgroundColor: theme.primaryColor), + child: new ListItem( + leading: new Icon(icon: Icons.delete, color: Colors.white, size: 36.0) + ) + ), + secondaryBackground: new Container( + decoration: new BoxDecoration(backgroundColor: theme.primaryColor), + child: new ListItem( + trailing: new Icon(icon: Icons.archive, color: Colors.white, size: 36.0) + ) + ), + child: new Container( + decoration: new BoxDecoration( + backgroundColor: theme.canvasColor, + border: new Border(bottom: new BorderSide(color: theme.dividerColor)) + ), + child: new ListItem( + title: new Text(item.name), + subtitle: new Text('${item.subject}\n${item.body}'), + isThreeLine: true + ) + ) + ); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + key: _scaffoldKey, + appBar: new AppBar( + title: new Text('Swipe items to dismiss'), + actions: [ + new PopupMenuButton( + onSelected: handleDemoAction, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: LeaveBehindDemoAction.reset, + child: new Text('Reset the list') + ), + new PopupMenuDivider(), + new CheckedPopupMenuItem( + value: LeaveBehindDemoAction.horizontalSwipe, + checked: _dismissDirection == DismissDirection.horizontal, + child: new Text('Hoizontal swipe') + ), + new CheckedPopupMenuItem( + value: LeaveBehindDemoAction.leftSwipe, + checked: _dismissDirection == DismissDirection.endToStart, + child: new Text('Only swipe left') + ), + new CheckedPopupMenuItem( + value: LeaveBehindDemoAction.rightSwipe, + checked: _dismissDirection == DismissDirection.startToEnd, + child: new Text('Only swipe right') + ) + ] + ) + ] + ), + body: new Block( + padding: new EdgeInsets.all(4.0), + children: leaveBehindItems.map(buildItem).toList() + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/list_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/list_demo.dart new file mode 100644 index 0000000000..d6714c3a04 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/list_demo.dart @@ -0,0 +1,205 @@ +// Copyright 2016 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'; + +class ListDemo extends StatefulWidget { + ListDemo({ Key key }) : super(key: key); + + static const String routeName = '/list'; + + @override + ListDemoState createState() => new ListDemoState(); +} + +class ListDemoState extends State { + final GlobalKey scaffoldKey = new GlobalKey(); + + PersistentBottomSheetController _bottomSheet; + MaterialListType _itemType = MaterialListType.threeLine; + bool _dense = false; + bool _showAvatars = true; + bool _showIcons = false; + bool _showDividers = false; + bool _reverseSort = false; + List items = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N' + ]; + + void changeItemType(MaterialListType type) { + setState(() { + _itemType = type; + }); + _bottomSheet?.setState(() { }); + } + + void showConfigurationSheet(BuildContext appContext) { + _bottomSheet = scaffoldKey.currentState.showBottomSheet((BuildContext bottomSheetContext) { + return new Container( + decoration: new BoxDecoration( + border: new Border(top: new BorderSide(color: Colors.black26)) + ), + child: new Block( + children: [ + new ListItem( + dense: true, + title: new Text('One-line'), + trailing: new Radio( + value: _showAvatars ? MaterialListType.oneLineWithAvatar : MaterialListType.oneLine, + groupValue: _itemType, + onChanged: changeItemType + ) + ), + new ListItem( + dense: true, + title: new Text('Two-line'), + trailing: new Radio( + value: MaterialListType.twoLine, + groupValue: _itemType, + onChanged: changeItemType + ) + ), + new ListItem( + dense: true, + title: new Text('Three-line'), + trailing: new Radio( + value: MaterialListType.threeLine, + groupValue: _itemType, + onChanged: changeItemType + ) + ), + new ListItem( + dense: true, + title: new Text('Show avatar'), + trailing: new Checkbox( + value: _showAvatars, + onChanged: (bool value) { + setState(() { + _showAvatars = value; + }); + _bottomSheet?.setState(() { }); + } + ) + ), + new ListItem( + dense: true, + title: new Text('Show icon'), + trailing: new Checkbox( + value: _showIcons, + onChanged: (bool value) { + setState(() { + _showIcons = value; + }); + _bottomSheet?.setState(() { }); + } + ) + ), + new ListItem( + dense: true, + title: new Text('Show dividers'), + trailing: new Checkbox( + value: _showDividers, + onChanged: (bool value) { + setState(() { + _showDividers = value; + }); + _bottomSheet?.setState(() { }); + } + ) + ), + new ListItem( + dense: true, + title: new Text('Dense layout'), + trailing: new Checkbox( + value: _dense, + onChanged: (bool value) { + setState(() { + _dense = value; + }); + _bottomSheet?.setState(() { }); + } + ) + ) + ] + ) + ); + }); + } + + Widget buildListItem(BuildContext context, String item) { + Widget secondary; + if (_itemType == MaterialListType.twoLine) { + secondary = new Text( + "Additional item information." + ); + } else if (_itemType == MaterialListType.threeLine) { + secondary = new Text( + "Even more additional list item information appears on line three." + ); + } + return new ListItem( + isThreeLine: _itemType == MaterialListType.threeLine, + dense: _dense, + leading: _showAvatars ? new CircleAvatar(child: new Text(item)) : null, + title: new Text('This item represents $item.'), + subtitle: secondary, + trailing: _showIcons ? new Icon(icon: Icons.info, color: Theme.of(context).disabledColor) : null + ); + } + + @override + Widget build(BuildContext context) { + final String layoutText = _dense ? " \u2013 Dense" : ""; + String itemTypeText; + switch(_itemType) { + case MaterialListType.oneLine: + case MaterialListType.oneLineWithAvatar: + itemTypeText = 'Single-line'; + break; + case MaterialListType.twoLine: + itemTypeText = 'Two-line'; + break; + case MaterialListType.threeLine: + itemTypeText = 'Three-line'; + break; + } + + Iterable listItems = items.map((String item) => buildListItem(context, item)); + if (_showDividers) + listItems = ListItem.divideItems(context: context, items: listItems); + + return new Scaffold( + key: scaffoldKey, + appBar: new AppBar( + title: new Text('Scrolling list\n$itemTypeText$layoutText'), + actions: [ + new IconButton( + icon: Icons.sort_by_alpha, + tooltip: 'Sort', + onPressed: () { + setState(() { + _reverseSort = !_reverseSort; + items.sort((String a, String b) => _reverseSort ? b.compareTo(a) : a.compareTo(b)); + }); + } + ), + new IconButton( + icon: Icons.more_vert, + tooltip: 'Show menu', + onPressed: () { showConfigurationSheet(context); } + ) + ] + ), + body: new OverscrollIndicator( + child: new Scrollbar( + child: new MaterialList( + type: _itemType, + padding: new EdgeInsets.symmetric(vertical: _dense ? 4.0 : 8.0), + children: listItems + ) + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/menu_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/menu_demo.dart new file mode 100644 index 0000000000..a5df0e16fd --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/menu_demo.dart @@ -0,0 +1,216 @@ +// Copyright 2016 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'; + +class MenuDemo extends StatefulWidget { + MenuDemo({ Key key }) : super(key: key); + + static const String routeName = '/menu'; + + @override + MenuDemoState createState() => new MenuDemoState(); +} + +class MenuDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + + final String _simpleValue1 = 'Menu item value one'; + final String _simpleValue2 = 'Menu item value two'; + final String _simpleValue3 = 'Menu item value three'; + String _simpleValue; + + final String _checkedValue1 = 'One'; + final String _checkedValue2 = 'Two'; + final String _checkedValue3 = 'Free'; + final String _checkedValue4 = 'Four'; + List _checkedValues; + + @override + void initState() { + super.initState(); + _simpleValue = _simpleValue2; + _checkedValues = [_checkedValue3]; + } + + void showInSnackBar(String value) { + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text(value) + )); + } + + void showMenuSelection(String value) { + if ([_simpleValue1, _simpleValue2, _simpleValue3].contains(value)) + _simpleValue = value; + showInSnackBar('You selected: $value'); + } + + void showCheckedMenuSelections(String value) { + if (_checkedValues.contains(value)) + _checkedValues.remove(value); + else + _checkedValues.add(value); + + showInSnackBar('Checked $_checkedValues'); + } + + bool isChecked(String value) => _checkedValues.contains(value); + + @override + Widget build(BuildContext context) { + return new Scaffold( + key: _scaffoldKey, + appBar: new AppBar( + title: new Text('Menus'), + actions: [ + new PopupMenuButton( + onSelected: showMenuSelection, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: 'Toolbar menu', + child: new Text('Toolbar menu') + ), + new PopupMenuItem( + value: 'Right here', + child: new Text('Right here') + ), + new PopupMenuItem( + value: 'Hooray!', + child: new Text('Hooray!') + ), + ] + ) + ] + ), + body: new Block( + padding: const EdgeInsets.symmetric(vertical: 8.0), + children: [ + // Pressing the PopupMenuButton on the right of this item shows + // a simple menu with one disabled item. Typically the contents + // of this "contextual menu" would reflect the app's state. + new ListItem( + title: new Text('An item with a context menu button'), + trailing: new PopupMenuButton( + padding: EdgeInsets.zero, + onSelected: showMenuSelection, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: _simpleValue1, + child: new Text('Context menu item one') + ), + new PopupMenuItem( + enabled: false, + child: new Text('A disabled menu item') + ), + new PopupMenuItem( + value: _simpleValue3, + child: new Text('Context menu item three') + ), + ] + ) + ), + // Pressing the PopupMenuButton on the right of this item shows + // a menu whose items have text labels and icons and a divider + // That separates the first three items from the last one. + new ListItem( + title: new Text('An item with a sectioned menu'), + trailing: new PopupMenuButton( + padding: EdgeInsets.zero, + onSelected: showMenuSelection, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: 'Preview', + child: new ListItem( + leading: new Icon(icon: Icons.visibility), + title: new Text('Preview') + ) + ), + new PopupMenuItem( + value: 'Share', + child: new ListItem( + leading: new Icon(icon: Icons.person_add), + title: new Text('Share') + ) + ), + new PopupMenuItem( + value: 'Get Link', + child: new ListItem( + leading: new Icon(icon: Icons.link), + title: new Text('Get link') + ) + ), + new PopupMenuDivider(), + new PopupMenuItem( + value: 'Remove', + child: new ListItem( + leading: new Icon(icon: Icons.delete), + title: new Text('Remove') + ) + ) + ] + ) + ), + // This entire list item is a PopupMenuButton. Tapping anywhere shows + // a menu whose current value is highlighted and aligned over the + // list item's center line. + new PopupMenuButton( + padding: EdgeInsets.zero, + initialValue: _simpleValue, + onSelected: showMenuSelection, + child: new ListItem( + title: new Text('An item with a simple menu'), + subtitle: new Text(_simpleValue) + ), + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: _simpleValue1, + child: new Text(_simpleValue1) + ), + new PopupMenuItem( + value: _simpleValue2, + child: new Text(_simpleValue2) + ), + new PopupMenuItem( + value: _simpleValue3, + child: new Text(_simpleValue3) + ) + ] + ), + // Pressing the PopupMenuButton on the right of this item shows a menu + // whose items have checked icons that reflect this app's state. + new ListItem( + title: new Text('An item with a checklist menu'), + trailing: new PopupMenuButton( + padding: EdgeInsets.zero, + onSelected: showCheckedMenuSelections, + itemBuilder: (BuildContext context) => >[ + new CheckedPopupMenuItem( + value: _checkedValue1, + checked: isChecked(_checkedValue1), + child: new Text(_checkedValue1) + ), + new CheckedPopupMenuItem( + value: _checkedValue2, + enabled: false, + checked: isChecked(_checkedValue2), + child: new Text(_checkedValue2) + ), + new CheckedPopupMenuItem( + value: _checkedValue3, + checked: isChecked(_checkedValue3), + child: new Text(_checkedValue3) + ), + new CheckedPopupMenuItem( + value: _checkedValue4, + checked: isChecked(_checkedValue4), + child: new Text(_checkedValue4) + ) + ] + ) + ) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/modal_bottom_sheet_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/modal_bottom_sheet_demo.dart new file mode 100644 index 0000000000..d404e50e7b --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/modal_bottom_sheet_demo.dart @@ -0,0 +1,39 @@ +// Copyright 2015 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'; + +final TextStyle _kTextStyle = new TextStyle( + color: Colors.indigo[400], + fontSize: 24.0 +); + +class ModalBottomSheetDemo extends StatelessWidget { + static const String routeName = '/modal-bottom-sheet'; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Modal bottom sheet')), + body: new Center( + child: new RaisedButton( + child: new Text('SHOW BOTTOM SHEET'), + onPressed: () { + showModalBottomSheet/**/(context: context, builder: (BuildContext context) { + return new Container( + child: new Padding( + padding: const EdgeInsets.all(32.0), + child: new Text('This is the modal bottom sheet. Click anywhere to dismiss.', + style: _kTextStyle, + textAlign: TextAlign.center + ) + ) + ); + }); + } + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/overscroll_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/overscroll_demo.dart new file mode 100644 index 0000000000..3ee1f02d1a --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/overscroll_demo.dart @@ -0,0 +1,95 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter/material.dart'; + +enum IndicatorType { overscroll, refresh } + +class OverscrollDemo extends StatefulWidget { + OverscrollDemo({ Key key }) : super(key: key); + + static const String routeName = '/overscroll'; + + @override + OverscrollDemoState createState() => new OverscrollDemoState(); +} + +class OverscrollDemoState extends State { + static final List _items = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N' + ]; + + IndicatorType _type = IndicatorType.refresh; + + Future refresh() { + Completer completer = new Completer(); + new Timer(new Duration(seconds: 3), () { completer.complete(null); }); + return completer.future; + } + + + @override + Widget build(BuildContext context) { + String indicatorTypeText; + switch(_type) { + case IndicatorType.overscroll: + indicatorTypeText = 'Over-scroll indicator'; + break; + case IndicatorType.refresh: + indicatorTypeText = 'Refresh indicator'; + break; + } + + Widget body = new MaterialList( + type: MaterialListType.threeLine, + padding: const EdgeInsets.all(8.0), + children: _items.map((String item) { + return new ListItem( + isThreeLine: true, + leading: new CircleAvatar(child: new Text(item)), + title: new Text('This item represents $item.'), + subtitle: new Text('Even more additional list item information appears on line three.') + ); + }) + ); + switch(_type) { + case IndicatorType.overscroll: + body = new OverscrollIndicator(child: body); + break; + case IndicatorType.refresh: + body = new RefreshIndicator(child: body, refresh: refresh); + break; + } + + return new Scaffold( + appBar: new AppBar( + title: new Text('$indicatorTypeText'), + actions: [ + new IconButton( + icon: Icons.refresh, + tooltip: 'Pull to refresh', + onPressed: () { + setState(() { + _type = IndicatorType.refresh; + }); + } + ), + new IconButton( + icon: Icons.play_for_work, + tooltip: 'Over-scroll indicator', + onPressed: () { + setState(() { + _type = IndicatorType.overscroll; + }); + } + ) + ] + ), + body: body + ); + } + +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/page_selector_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/page_selector_demo.dart new file mode 100644 index 0000000000..7b7f0b9d3e --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/page_selector_demo.dart @@ -0,0 +1,81 @@ +// Copyright 2015 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'; + +class PageSelectorDemo extends StatelessWidget { + + static const String routeName = '/page-selector'; + + void _handleArrowButtonPress(BuildContext context, int delta) { + final TabBarSelectionState selection = TabBarSelection.of/**/(context); + if (!selection.valueIsChanging) + selection.value = selection.values[(selection.index + delta).clamp(0, selection.values.length - 1)]; + } + + @override + Widget build(BuildContext notUsed) { // Can't find the TabBarSelection from this context. + final List icons = [ + Icons.event, + Icons.home, + Icons.android, + Icons.alarm, + Icons.face, + Icons.language, + ]; + + return new Scaffold( + appBar: new AppBar(title: new Text('Page selector')), + body: new TabBarSelection( + values: icons, + child: new Builder( + builder: (BuildContext context) { + final Color color = Theme.of(context).accentColor; + return new Column( + children: [ + new Container( + margin: const EdgeInsets.only(top: 16.0), + child: new Row( + children: [ + new IconButton( + icon: Icons.arrow_back, + color: color, + onPressed: () { _handleArrowButtonPress(context, -1); }, + tooltip: 'Page back' + ), + new TabPageSelector(), + new IconButton( + icon: Icons.arrow_forward, + color: color, + onPressed: () { _handleArrowButtonPress(context, 1); }, + tooltip: 'Page forward' + ) + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween + ) + ), + new Flexible( + child: new TabBarView( + children: icons.map((IconData icon) { + return new Container( + key: new ObjectKey(icon), + padding: const EdgeInsets.all(12.0), + child: new Card( + child: new Center( + child: new Icon(icon: icon, size: 128.0, color: color) + ) + ) + ); + }) + .toList() + ) + ) + ] + ); + } + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart new file mode 100644 index 0000000000..cb3c3b05c5 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/persistent_bottom_sheet_demo.dart @@ -0,0 +1,73 @@ +// Copyright 2015 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'; + +final TextStyle _kTextStyle = new TextStyle( + color: Colors.indigo[400], + fontSize: 24.0 +); + +class PersistentBottomSheetDemo extends StatefulWidget { + static const String routeName = '/persistent-bottom-sheet'; + + @override + _PersistentBottomSheetDemoState createState() => new _PersistentBottomSheetDemoState(); +} + +class _PersistentBottomSheetDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + + VoidCallback _showBottomSheetCallback; + + @override + void initState() { + super.initState(); + _showBottomSheetCallback = showBottomSheet; + } + + + void showBottomSheet() { + setState(() { // disable the button + _showBottomSheetCallback = null; + }); + _scaffoldKey.currentState.showBottomSheet/**/((BuildContext context) { + return new Container( + decoration: new BoxDecoration( + border: new Border(top: new BorderSide(color: Colors.black26)) + ), + child: new Padding( + padding: const EdgeInsets.all(32.0), + child: new Text('This is a Material persistent bottom sheet. Drag downwards to dismiss it.', + style: _kTextStyle, + textAlign: TextAlign.center + ) + ) + ); + }) + .closed.then((_) { + setState(() { // re-enable the button + _showBottomSheetCallback = showBottomSheet; + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + key: _scaffoldKey, + appBar: new AppBar(title: new Text('Persistent bottom sheet')), + floatingActionButton: new FloatingActionButton( + child: new Icon(icon: Icons.add), + backgroundColor: Colors.redAccent[200] + ), + body: new Center( + child: new RaisedButton( + onPressed: _showBottomSheetCallback, + child: new Text('SHOW BOTTOM SHEET') + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/progress_indicator_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/progress_indicator_demo.dart new file mode 100644 index 0000000000..8c4e363e65 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/progress_indicator_demo.dart @@ -0,0 +1,113 @@ +// Copyright 2015 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'; + +class ProgressIndicatorDemo extends StatefulWidget { + static const String routeName = '/progress-indicator'; + + @override + _ProgressIndicatorDemoState createState() => new _ProgressIndicatorDemoState(); +} + +class _ProgressIndicatorDemoState extends State { + AnimationController _controller; + Animation _animation; + + @override + void initState() { + super.initState(); + _controller = new AnimationController( + duration: const Duration(milliseconds: 1500) + )..forward(); + + _animation = new CurvedAnimation( + parent: _controller, + curve: new Interval(0.0, 0.9, curve: Curves.ease), + reverseCurve: Curves.ease + )..addStatusListener((AnimationStatus status) { + if (status == AnimationStatus.dismissed) + _controller.forward(); + else if (status == AnimationStatus.completed) + _controller.reverse(); + }); + } + + @override + void dispose() { + _controller.stop(); + super.dispose(); + } + + void _handleTap() { + setState(() { + // valueAnimation.isAnimating is part of our build state + if (_controller.isAnimating) { + _controller.stop(); + } else { + switch (_controller.status) { + case AnimationStatus.dismissed: + case AnimationStatus.forward: + _controller.forward(); + break; + case AnimationStatus.reverse: + case AnimationStatus.completed: + _controller.reverse(); + break; + } + } + }); + } + + Widget _buildIndicators(BuildContext context, Widget child) { + List indicators = [ + new SizedBox( + width: 200.0, + child: new LinearProgressIndicator() + ), + new LinearProgressIndicator(), + new LinearProgressIndicator(), + new LinearProgressIndicator(value: _animation.value), + new CircularProgressIndicator(), + new SizedBox( + width: 20.0, + height: 20.0, + child: new CircularProgressIndicator(value: _animation.value) + ), + new SizedBox( + width: 50.0, + height: 30.0, + child: new CircularProgressIndicator(value: _animation.value) + ), + new Text('${(_animation.value * 100.0).toStringAsFixed(1)}%${ _controller.isAnimating ? "" : " (paused)" }') + ]; + return new Column( + children: indicators + .map((Widget c) => new Container(child: c, margin: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0))) + .toList(), + mainAxisAlignment: MainAxisAlignment.center + ); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Progress indicators')), + body: new DefaultTextStyle( + style: Theme.of(context).textTheme.title, + child: new GestureDetector( + onTap: _handleTap, + behavior: HitTestBehavior.opaque, + child: new Container( + padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0), + child: new AnimatedBuilder( + animation: _animation, + builder: _buildIndicators + ) + ) + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/scrollable_tabs_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/scrollable_tabs_demo.dart new file mode 100644 index 0000000000..2f00f0e3e6 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/scrollable_tabs_demo.dart @@ -0,0 +1,111 @@ +// Copyright 2015 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'; + +enum TabsDemoStyle { + iconsAndText, + iconsOnly, + textOnly +} + +class ScrollableTabsDemo extends StatefulWidget { + static const String routeName = '/scrollable-tabs'; + + @override + ScrollableTabsDemoState createState() => new ScrollableTabsDemoState(); +} + +class ScrollableTabsDemoState extends State { + final List icons = [ + Icons.event, + Icons.home, + Icons.android, + Icons.alarm, + Icons.face, + Icons.language, + ]; + + final Map labels = { + Icons.event: 'EVENT', + Icons.home: 'HOME', + Icons.android: 'ANDROID', + Icons.alarm: 'ALARM', + Icons.face: 'FACE', + Icons.language: 'LANGUAGE', + }; + + TabsDemoStyle _demoStyle = TabsDemoStyle.iconsAndText; + + void changeDemoStyle(TabsDemoStyle style) { + setState(() { + _demoStyle = style; + }); + } + + @override + Widget build(BuildContext context) { + final Color iconColor = Theme.of(context).accentColor; + return new TabBarSelection( + values: icons, + child: new Scaffold( + appBar: new AppBar( + title: new Text('Scrollable tabs'), + actions: [ + new PopupMenuButton( + onSelected: changeDemoStyle, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: TabsDemoStyle.iconsAndText, + child: new Text('Icons and text') + ), + new PopupMenuItem( + value: TabsDemoStyle.iconsOnly, + child: new Text('Icons only') + ), + new PopupMenuItem( + value: TabsDemoStyle.textOnly, + child: new Text('Text only') + ), + ] + ) + ], + tabBar: new TabBar( + isScrollable: true, + labels: new Map.fromIterable( + icons, + value: (IconData icon) { + switch(_demoStyle) { + case TabsDemoStyle.iconsAndText: + return new TabLabel(text: labels[icon], icon: icon); + case TabsDemoStyle.iconsOnly: + return new TabLabel(icon: icon); + case TabsDemoStyle.textOnly: + return new TabLabel(text: labels[icon]); + } + } + ) + ) + ), + body: new TabBarView( + children: icons.map((IconData icon) { + return new Container( + key: new ObjectKey(icon), + padding: const EdgeInsets.all(12.0), + child:new Card( + child: new Center( + child: new Icon( + icon: icon, + color: iconColor, + size: 128.0 + ) + ) + ) + ); + }).toList() + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/scrolling_techniques_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/scrolling_techniques_demo.dart new file mode 100644 index 0000000000..1a9b2ed434 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/scrolling_techniques_demo.dart @@ -0,0 +1,159 @@ +// Copyright 2016 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 'flexible_space_demo.dart'; + +class _BarGraphic extends StatelessWidget { + _BarGraphic({ Key key, this.height, this.color, this.leftText, this.rightText: '' }) + : super(key: key) { + assert(height != null); + assert(color != null); + assert(leftText != null); + } + + final double height; + final Color color; + final String leftText; + final String rightText; + + @override + Widget build(BuildContext context) { + return new Container( + height: height, + width: 200.0, + padding: const EdgeInsets.symmetric(horizontal: 16.0), + decoration: new BoxDecoration(backgroundColor: color), + child: new DefaultTextStyle( + style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Text(leftText), + new Text(rightText) + ] + ) + ) + ); + } +} + +class _StatusBarGraphic extends _BarGraphic { + _StatusBarGraphic() : super( + height: 24.0, + color: Colors.green[400], + leftText: 'Status Bar', + rightText: '24dp' + ); +} + +class _AppBarGraphic extends _BarGraphic { + _AppBarGraphic() : super( + height: 48.0, + color: Colors.blue[400], + leftText: 'Tool Bar', + rightText: '48dp' + ); +} + +class _TabBarGraphic extends _BarGraphic { + _TabBarGraphic() : super( + height: 48.0, + color: Colors.purple[400], + leftText: 'Tab Bar', + rightText: '56dp' + ); +} + +class _FlexibleSpaceGraphic extends _BarGraphic { + _FlexibleSpaceGraphic() : super( + height: 128.0, + color: Colors.pink[400], + leftText: 'Flexible Space' + ); +} + +class _TechniqueItem extends StatelessWidget { + _TechniqueItem({ this.titleText, this.barGraphics, this.builder }); + + final String titleText; + final List barGraphics; + final WidgetBuilder builder; + + void showDemo(BuildContext context) { + Navigator.push(context, new MaterialPageRoute(builder: builder)); + } + + @override + Widget build(BuildContext context) { + return new Card( + child: new InkWell( + onTap: () { showDemo(context); }, + child: new Padding( + padding: const EdgeInsets.all(16.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children :[ + new Text(titleText), + new Column(children: barGraphics) + ] + ) + ) + ) + ); + } +} + +const String _introText = + "An AppBar is a combination of a ToolBar and a TabBar or a flexible space " + "Widget that is managed by the Scaffold. The Scaffold pads the ToolBar so that " + "it appears behind the device's status bar. When a flexible space Widget is " + "specified it is stacked on top of the ToolBar."; + +class ScrollingTechniquesDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Scrolling techniques')), + body: new Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: new Block( + children: [ + new Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 32.0), + child: new Text(_introText, style: Theme.of(context).textTheme.caption) + ), + new _TechniqueItem( + builder: (BuildContext context) => new FlexibleSpaceDemo(), + titleText: 'Standard', + barGraphics: [ + new _StatusBarGraphic(), + new _AppBarGraphic() + ] + ), + new _TechniqueItem( + titleText: 'Tabs', + builder: (BuildContext context) => new FlexibleSpaceDemo(), + barGraphics: [ + new _StatusBarGraphic(), + new _AppBarGraphic(), + new _TabBarGraphic() + ] + ), + new _TechniqueItem( + titleText: 'Flexible', + builder: (BuildContext context) => new FlexibleSpaceDemo(), + barGraphics: [ + new _StatusBarGraphic(), + new _AppBarGraphic(), + new _FlexibleSpaceGraphic() + ] + ) + ] + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/selection_controls_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/selection_controls_demo.dart new file mode 100644 index 0000000000..29213d7f2b --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/selection_controls_demo.dart @@ -0,0 +1,180 @@ +// Copyright 2015 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 '../gallery/demo.dart'; + +const String _checkboxText = + "# Checkboxes\n" + "Checkboxes allow the user to select multiple options from a set."; + +const String _checkboxCode = 'selectioncontrols_checkbox'; + +const String _radioText = + "# Radio buttons\n" + "Radio buttons allow the user to select one option from a set. Use radio " + "buttons for exclusive selection if you think that the user needs to see " + "all available options side-by-side."; + +const String _radioCode = 'selectioncontrols_radio'; + +const String _switchText = + "# Switches\n" + "On/off switches toggle the state of a single settings option. The option " + "that the switch controls, as well as the state it’s in, should be made " + "clear from the corresponding inline label."; + +const String _switchCode = 'selectioncontrols_switch'; + +class SelectionControlsDemo extends StatefulWidget { + static const String routeName = '/selection-controls'; + + @override + _SelectionControlsDemoState createState() => new _SelectionControlsDemoState(); +} + +class _SelectionControlsDemoState extends State { + @override + Widget build(BuildContext context) { + List demos = [ + new ComponentDemoTabData( + tabName: "CHECKBOX", + description: _checkboxText, + widget: buildCheckbox(), + exampleCodeTag: _checkboxCode + ), + new ComponentDemoTabData( + tabName: "RADIO", + description: _radioText, + widget: buildRadio(), + exampleCodeTag: _radioCode + ), + new ComponentDemoTabData( + tabName: "SWITCH", + description: _switchText, + widget: buildSwitch(), + exampleCodeTag: _switchCode + ) + ]; + + return new TabbedComponentDemoScaffold( + title: 'Selection controls', + demos: demos + ); + } + + bool checkboxValueA = true; + bool checkboxValueB = false; + int radioValue = 0; + bool switchValue = false; + + void handleRadioValueChanged(int value) { + setState(() { + radioValue = value; + }); + } + + Widget buildCheckbox() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new Column( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Checkbox(value: checkboxValueA, onChanged: (bool value) { + setState(() { + checkboxValueA = value; + }); + }), + new Checkbox(value: checkboxValueB, onChanged: (bool value) { + setState(() { + checkboxValueB = value; + }); + }) + ] + ), + new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + // Disabled checkboxes + new Checkbox(value: true), + new Checkbox(value: false) + ] + ) + ] + ) + ); + } + + Widget buildRadio() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new Column( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Radio( + value: 0, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ), + new Radio( + value: 1, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ), + new Radio( + value: 2, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ) + ] + ), + // Disabled radio buttons + new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Radio( + value: 0, + groupValue: 0 + ), + new Radio( + value: 1, + groupValue: 0 + ), + new Radio( + value: 2, + groupValue: 0 + ) + ] + ) + ] + ) + ); + } + + Widget buildSwitch() { + return new Align( + alignment: new FractionalOffset(0.5, 0.4), + child: new Row( + mainAxisAlignment: MainAxisAlignment.collapse, + children: [ + new Switch(value: switchValue, onChanged: (bool value) { + setState(() { + switchValue = value; + }); + }), + // Disabled switches + new Switch(value: true), + new Switch(value: false) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/slider_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/slider_demo.dart new file mode 100644 index 0000000000..78d40eee05 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/slider_demo.dart @@ -0,0 +1,56 @@ +// Copyright 2015 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'; + +class SliderDemo extends StatefulWidget { + static const String routeName = '/slider'; + + @override + _SliderDemoState createState() => new _SliderDemoState(); +} + +class _SliderDemoState extends State { + double _value = 25.0; + double _discreteValue = 20.0; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Sliders')), + body: new Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + new Center( + child: new Slider( + value: _value, + min: 0.0, + max: 100.0, + onChanged: (double value) { + setState(() { + _value = value; + }); + } + ) + ), + new Center(child: new Slider(value: _value / 100.0)), + new Center( + child: new Slider( + value: _discreteValue, + min: 0.0, + max: 100.0, + divisions: 5, + label: '${_discreteValue.round()}', + onChanged: (double value) { + setState(() { + _discreteValue = value; + }); + } + ) + ), + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/snack_bar_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/snack_bar_demo.dart new file mode 100644 index 0000000000..f0ed109bad --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/snack_bar_demo.dart @@ -0,0 +1,84 @@ +// Copyright 2016 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/widgets.dart'; + +const String _text1 = + "Snackbars provide lightweight feedback about an operation by " + "showing a brief message at the bottom of the screen. Snackbars " + "can contain an action."; + +const String _text2 = + "Snackbars should contain a single line of text directly related " + "to the operation performed. They cannot contain icons."; + +const String _text3 = + "By default snackbars automatically disappear after a few seconds "; + +class SnackBarDemo extends StatefulWidget { + SnackBarDemo({ Key key }) : super(key: key); + + static const String routeName = '/snack-bar'; + + @override + _SnackBarDemoState createState() => new _SnackBarDemoState(); +} + +class _SnackBarDemoState extends State { + int _snackBarIndex = 1; + + Widget buildBody(BuildContext context) { + return new Padding( + padding: const EdgeInsets.all(24.0), + child: new Block( + children: [ + new Text(_text1), + new Text(_text2), + new Center( + child: new RaisedButton( + child: new Text('SHOW A SNACKBAR'), + onPressed: () { + final int thisSnackBarIndex = _snackBarIndex++; + Scaffold.of(context).showSnackBar(new SnackBar( + content: new Text('This is snackbar #$thisSnackBarIndex.'), + action: new SnackBarAction( + label: 'ACTION', + onPressed: () { + Scaffold.of(context).showSnackBar(new SnackBar( + content: new Text('You pressed snackbar $thisSnackBarIndex\'s action.') + )); + } + ) + )); + } + ) + ), + new Text(_text3), + ] + .map((Widget child) { + return new Container( + margin: const EdgeInsets.symmetric(vertical: 12.0), + child: child + ); + }) + .toList() + ) + ); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Snackbar') + ), + body: new Builder( + // Create an inner BuildContext so that the snackBar onPressed methods + // can refer to the Scaffold with Scaffold.of(). + builder: buildBody + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/tabs_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/tabs_demo.dart new file mode 100644 index 0000000000..ab26272b5d --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/tabs_demo.dart @@ -0,0 +1,82 @@ +// Copyright 2015 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'; + +class _Page { + _Page({ this.label }); + + final GlobalKey> key = new GlobalKey>(); + final String label; +} + +final List<_Page> _pages = <_Page>[ + new _Page(label: 'ONE'), + new _Page(label: 'TWO'), + new _Page(label: 'FREE'), + new _Page(label: 'FOUR') +]; + +class TabsDemo extends StatefulWidget { + static const String routeName = '/tabs'; + + @override + TabsDemoState createState() => new TabsDemoState(); +} + +class TabsDemoState extends State { + _Page _selectedPage; + double _scrollOffset = 0.0; + + @override + void initState() { + super.initState(); + _selectedPage = _pages[0]; + } + + @override + Widget build(BuildContext context) { + final double statusBarHeight = MediaQuery.of(context).padding.top; + return new TabBarSelection<_Page>( + values: _pages, + onChanged: (_Page value) { + setState(() { + _selectedPage = value; + _selectedPage.key.currentState.scrollTo(_scrollOffset); + }); + }, + child: new Scaffold( + appBarBehavior: AppBarBehavior.under, + appBar: new AppBar( + title: new Text('Tabs and scrolling'), + tabBar: new TabBar<_Page>( + labels: new Map<_Page, TabLabel>.fromIterable(_pages, value: (_Page page) { + return new TabLabel(text: page.label); + }) + ) + ), + body: new TabBarView<_Page>( + children: _pages.map((_Page page) { + return new Block( + padding: new EdgeInsets.only(top: kTextTabBarHeight + kToolBarHeight + statusBarHeight), + scrollableKey: page.key, + onScroll: (double value) { _scrollOffset = value; }, + children: new List.generate(6, (int i) { + return new Container( + padding: const EdgeInsets.all(8.0), + height: 192.0, + child: new Card( + child: new Center( + child: new Text('Tab $page.label, item $i') + ) + ) + ); + }) + ); + }).toList() + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/tabs_fab_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/tabs_fab_demo.dart new file mode 100644 index 0000000000..6dbaec1bef --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/tabs_fab_demo.dart @@ -0,0 +1,118 @@ +// Copyright 2015 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'; + +class _Page { + _Page({ this.label, this.colors, this.icon }); + + final String label; + final Map colors; + final IconData icon; + + TabLabel get tabLabel => new TabLabel(text: label.toUpperCase()); + Color get labelColor => colors != null ? colors[300] : Colors.grey[300]; + bool get fabDefined => colors != null && icon != null; + Color get fabColor => colors[400]; + Icon get fabIcon => new Icon(icon: icon); + Key get fabKey => new ValueKey(fabColor); +} + +const String _explanatoryText = + "When the Scaffold's floating action button changes, the new button fades and " + "turns into view. In this demo, changing tabs can cause the app to be rebuilt " + "with a FloatingActionButton that the Scaffold distinguishes from the others " + "by its key."; + +class TabsFabDemo extends StatefulWidget { + static const String routeName = '/tabs-fab'; + + @override + _TabsFabDemoState createState() => new _TabsFabDemoState(); +} + +class _TabsFabDemoState extends State { + final GlobalKey scaffoldKey = new GlobalKey(); + final List<_Page> pages = <_Page>[ + new _Page(label: 'Blue', colors: Colors.indigo, icon: Icons.add), + new _Page(label: 'Eco', colors: Colors.green, icon: Icons.create), + new _Page(label: 'No'), + new _Page(label: 'Teal', colors: Colors.teal, icon: Icons.add), + new _Page(label: 'Red', colors: Colors.red, icon: Icons.create), + ]; + _Page selectedPage; + + @override + void initState() { + super.initState(); + selectedPage = pages[0]; + } + + void _handleTabSelection(_Page page) { + setState(() { + selectedPage = page; + }); + } + + void _showExplanatoryText() { + scaffoldKey.currentState.showBottomSheet((BuildContext context) { + return new Container( + decoration: new BoxDecoration( + border: new Border(top: new BorderSide(color: Theme.of(context).dividerColor)) + ), + child: new Padding( + padding: const EdgeInsets.all(32.0), + child: new Text(_explanatoryText, style: Theme.of(context).textTheme.subhead) + ) + ); + }); + } + + Widget buildTabView(_Page page) { + return new Builder( + builder: (BuildContext context) { + return new Container( + key: new ValueKey(page.label), + padding: const EdgeInsets.fromLTRB(48.0, 48.0, 48.0, 96.0), + child: new Card( + child: new Center( + child: new Text(page.label, + style: new TextStyle( + color: page.labelColor, + fontSize: 32.0 + ), + textAlign: TextAlign.center + ) + ) + ) + ); + } + ); + } + + @override + Widget build(BuildContext context) { + return new TabBarSelection<_Page>( + values: pages, + onChanged: _handleTabSelection, + child: new Scaffold( + key: scaffoldKey, + appBar: new AppBar( + title: new Text('FAB per tab'), + tabBar: new TabBar<_Page>( + labels: new Map<_Page, TabLabel>.fromIterable(pages, value: (_Page page) => page.tabLabel) + ) + ), + floatingActionButton: !selectedPage.fabDefined ? null : new FloatingActionButton( + key: selectedPage.fabKey, + tooltip: 'Show explanation', + backgroundColor: selectedPage.fabColor, + child: selectedPage.fabIcon, + onPressed: _showExplanatoryText + ), + body: new TabBarView<_Page>(children: pages.map(buildTabView).toList()) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/text_field_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/text_field_demo.dart new file mode 100644 index 0000000000..ec991537fd --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/text_field_demo.dart @@ -0,0 +1,120 @@ +// Copyright 2016 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'; + +class TextFieldDemo extends StatefulWidget { + TextFieldDemo({ Key key }) : super(key: key); + + static const String routeName = '/text-field'; + + @override + TextFieldDemoState createState() => new TextFieldDemoState(); +} + +class PersonData { + String name; + String phoneNumber; + String password; +} + +class TextFieldDemoState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + + PersonData person = new PersonData(); + + void showInSnackBar(String value) { + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text(value) + )); + } + + void _handleSubmitted() { + showInSnackBar('${person.name}\'s phone number is ${person.phoneNumber}'); + } + + String _validateName(String value) { + if (value.isEmpty) + return 'Name is required.'; + RegExp nameExp = new RegExp(r'^[A-za-z ]+$'); + if (!nameExp.hasMatch(value)) + return 'Please enter only alphabetical characters.'; + return null; + } + + String _validatePhoneNumber(String value) { + RegExp phoneExp = new RegExp(r'^\d\d\d-\d\d\d\-\d\d\d\d$'); + if (!phoneExp.hasMatch(value)) + return '###-###-#### - Please enter a valid phone number.'; + return null; + } + + String _validatePassword(String value) { + if (person.password == null || person.password.isEmpty) + return 'Please choose a password.'; + if (person.password != value) + return 'Passwords don\'t match'; + return null; + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + key: _scaffoldKey, + appBar: new AppBar( + title: new Text('Text fields') + ), + body: new Form( + onSubmitted: _handleSubmitted, + child: new Block( + padding: const EdgeInsets.all(8.0), + children: [ + new Input( + hintText: 'What do people call you?', + labelText: 'Name', + formField: new FormField( + // TODO(mpcomplete): replace with person#name= + setter: (String val) { person.name = val; }, + validator: _validateName + ) + ), + new Input( + hintText: 'Where can we reach you?', + labelText: 'Phone Number', + formField: new FormField( + setter: (String val) { person.phoneNumber = val; }, + validator: _validatePhoneNumber + ) + ), + new Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Flexible( + child: new Input( + hintText: 'How do you log in?', + labelText: 'New Password', + hideText: true, + formField: new FormField( + setter: (String val) { person.password = val; } + ) + ) + ), + new Flexible( + child: new Input( + hintText: 'How do you log in?', + labelText: 'Re-type Password', + hideText: true, + formField: new FormField( + validator: _validatePassword + ) + ) + ) + ] + ) + ] + ) + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/time_picker_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/time_picker_demo.dart new file mode 100644 index 0000000000..06b048a9c6 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/time_picker_demo.dart @@ -0,0 +1,48 @@ +// Copyright 2015 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 'dart:async'; + +import 'package:flutter/material.dart'; + +class TimePickerDemo extends StatefulWidget { + static const String routeName = '/time-picker'; + + @override + _TimePickerDemoState createState() => new _TimePickerDemoState(); +} + +class _TimePickerDemoState extends State { + TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 28); + + Future _handleSelectTime() async { + TimeOfDay picked = await showTimePicker( + context: context, + initialTime: _selectedTime + ); + if (picked != _selectedTime) { + setState(() { + _selectedTime = picked; + }); + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Time picker')), + body: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text('$_selectedTime'), + new SizedBox(height: 20.0), + new RaisedButton( + onPressed: _handleSelectTime, + child: new Text('SELECT TIME') + ), + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/tooltip_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/tooltip_demo.dart new file mode 100644 index 0000000000..b9b41cba8a --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/tooltip_demo.dart @@ -0,0 +1,68 @@ +// Copyright 2016 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'; + +const String _introText = + "Tooltips are short identifying messages that briefly appear in response to " + "a long press. Tooltip messages are also used by services that make Flutter " + "apps accessible, like screen readers."; + +class TooltipDemo extends StatelessWidget { + + static const String routeName = '/tooltips'; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + return new Scaffold( + appBar: new AppBar( + title: new Text('Tooltips') + ), + body: new Builder( + builder: (BuildContext context) { + return new Block( + children: [ + new Text(_introText, style: theme.textTheme.subhead), + new Row( + children: [ + new Text('Long press the ', style: theme.textTheme.subhead), + new Tooltip( + message: 'call icon', + child: new Icon( + size: 18.0, + icon: Icons.call, + color: theme.primaryColor + ) + ), + new Text(' icon.', style: theme.textTheme.subhead) + ] + ), + new Center( + child: new IconButton( + size: 48.0, + icon: Icons.call, + color: theme.primaryColor, + tooltip: 'place a phone call', + onPressed: () { + Scaffold.of(context).showSnackBar(new SnackBar( + content: new Text('That was an ordinary tap.') + )); + } + ) + ) + ] + .map((Widget widget) { + return new Padding( + padding: const EdgeInsets.only(top: 16.0, left: 16.0, right: 16.0), + child: widget + ); + }) + .toList() + ); + } + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/two_level_list_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/two_level_list_demo.dart new file mode 100644 index 0000000000..215fb06f42 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/two_level_list_demo.dart @@ -0,0 +1,32 @@ +// Copyright 2016 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'; + +class TwoLevelListDemo extends StatelessWidget { + static const String routeName = '/two-level-list'; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar(title: new Text('Expand/collapse list control')), + body: new TwoLevelList( + type: MaterialListType.oneLine, + children: [ + new TwoLevelListItem(title: new Text('Top')), + new TwoLevelSublist( + title: new Text('Sublist'), + children: [ + new TwoLevelListItem(title: new Text('One')), + new TwoLevelListItem(title: new Text('Two')), + new TwoLevelListItem(title: new Text('Free')), + new TwoLevelListItem(title: new Text('Four')) + ] + ), + new TwoLevelListItem(title: new Text('Bottom')) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/typography_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/typography_demo.dart new file mode 100644 index 0000000000..5f3b7e0f94 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/typography_demo.dart @@ -0,0 +1,73 @@ +// Copyright 2016 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/widgets.dart'; + +class TextStyleItem extends StatelessWidget { + TextStyleItem({ Key key, this.name, this.style, this.text }) : super(key: key) { + assert(name != null); + assert(style != null); + assert(text != null); + } + + final String name; + final TextStyle style; + final String text; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle nameStyle = theme.textTheme.caption.copyWith(color: theme.textTheme.caption.color); + return new Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0), + child: new Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new SizedBox( + width: 64.0, + child: new Text(name, style: nameStyle) + ), + new Flexible( + child: new Text(text, style: style.copyWith(height: 1.0)) + ) + ] + ) + ); + } +} + +class TypographyDemo extends StatelessWidget { + static const String routeName = '/typography'; + + @override + Widget build(BuildContext context) { + final TextTheme textTheme = Theme.of(context).textTheme; + final List styleItems = [ + new TextStyleItem(name: 'Display 3', style: textTheme.display3, text: 'Regular 56sp'), + new TextStyleItem(name: 'Display 2', style: textTheme.display2, text: 'Regular 45sp'), + new TextStyleItem(name: 'Display 1', style: textTheme.display1, text: 'Regular 34sp'), + new TextStyleItem(name: 'Headline', style: textTheme.headline, text: 'Regular 24sp'), + new TextStyleItem(name: 'Title', style: textTheme.title, text: 'Medium 20sp'), + new TextStyleItem(name: 'Subheading', style: textTheme.subhead, text: 'Regular 16sp'), + new TextStyleItem(name: 'Body 2', style: textTheme.body2, text: 'Medium 14sp'), + new TextStyleItem(name: 'Body 1', style: textTheme.body1, text: 'Reguluar 14sp'), + new TextStyleItem(name: 'Caption', style: textTheme.caption, text: 'Regular 12sp'), + new TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp') + ]; + + if (MediaQuery.of(context).size.width > 500.0) { + styleItems.insert(0, new TextStyleItem( + name: 'Display 4', + style: textTheme.display4, + text: 'Light 112sp' + )); + } + + return new Scaffold( + appBar: new AppBar(title: new Text('Typography')), + body: new Block(children: styleItems) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/demo/weather_demo.dart b/examples/flutter_gallery/material_gallery/lib/demo/weather_demo.dart new file mode 100644 index 0000000000..defa7b1f45 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/demo/weather_demo.dart @@ -0,0 +1,559 @@ +// Copyright 2015 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 'dart:async'; +import 'dart:ui' as ui show Image; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_sprites/flutter_sprites.dart'; + +ImageMap _images; +SpriteSheet _sprites; + +enum WeatherType { + sun, + rain, + snow +} + +class WeatherDemo extends StatefulWidget { + WeatherDemo({ Key key }) : super(key: key); + + static const String routeName = '/weather'; + + @override + _WeatherDemoState createState() => new _WeatherDemoState(); +} + +class _WeatherDemoState extends State { + + Future _loadAssets(AssetBundle bundle) async { + _images = new ImageMap(bundle); + await _images.load([ + 'packages/flutter_gallery_assets/clouds-0.png', + 'packages/flutter_gallery_assets/clouds-1.png', + 'packages/flutter_gallery_assets/ray.png', + 'packages/flutter_gallery_assets/sun.png', + 'packages/flutter_gallery_assets/weathersprites.png', + 'packages/flutter_gallery_assets/icon-sun.png', + 'packages/flutter_gallery_assets/icon-rain.png', + 'packages/flutter_gallery_assets/icon-snow.png' + ]); + + String json = await DefaultAssetBundle.of(context).loadString('packages/flutter_gallery_assets/weathersprites.json'); + _sprites = new SpriteSheet(_images['packages/flutter_gallery_assets/weathersprites.png'], json); + } + + @override + void initState() { + super.initState(); + + AssetBundle bundle = DefaultAssetBundle.of(context); + _loadAssets(bundle).then((_) { + setState(() { + assetsLoaded = true; + weatherWorld = new WeatherWorld(); + }); + }); + } + + bool assetsLoaded = false; + + WeatherWorld weatherWorld; + + @override + Widget build(BuildContext context) { + if (!assetsLoaded) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Weather') + ), + body: new Container( + decoration: new BoxDecoration( + backgroundColor: const Color(0xff4aaafb) + ) + ) + ); + } + + return new Scaffold( + appBar: new AppBar( + title: new Text('Weather') + ), + body: new Material( + child: new Stack( + children: [ + new SpriteWidget(weatherWorld), + new Align( + alignment: new FractionalOffset(0.5, 0.8), + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new WeatherButton( + onPressed: () { + setState(() { + weatherWorld.weatherType = WeatherType.sun; + }); + }, + selected: weatherWorld.weatherType == WeatherType.sun, + icon: "packages/flutter_gallery_assets/icon-sun.png" + ), + new WeatherButton( + onPressed: () { + setState(() { + weatherWorld.weatherType = WeatherType.rain; + }); + }, + selected: weatherWorld.weatherType == WeatherType.rain, + icon: "packages/flutter_gallery_assets/icon-rain.png" + ), + new WeatherButton( + onPressed: () { + setState(() { + weatherWorld.weatherType = WeatherType.snow; + }); + }, + selected: weatherWorld.weatherType == WeatherType.snow, + icon: "packages/flutter_gallery_assets/icon-snow.png" + ) + ] + ) + ) + ] + ) + ) + ); + } +} + +const double _kWeatherButtonSize = 56.0; +const double _kWeatherIconSize = 36.0; + +class WeatherButton extends StatelessWidget { + WeatherButton({ this.icon, this.selected, this.onPressed, Key key }) : super(key: key); + + final String icon; + final bool selected; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + Color color; + if (selected) + color = Theme.of(context).primaryColor; + else + color = const Color(0x33000000); + + return new Padding( + padding: const EdgeInsets.all(15.0), + child: new Material( + color: color, + type: MaterialType.circle, + elevation: 0, + child: new Container( + width: _kWeatherButtonSize, + height: _kWeatherButtonSize, + child: new InkWell( + onTap: onPressed, + child: new Center( + child: new AssetImage( + name: icon, + width: _kWeatherIconSize, + height: _kWeatherIconSize + ) + ) + ) + ) + ) + ); + } +} + +const List _kBackgroundColorsTop = const [ + const Color(0xff5ebbd5), + const Color(0xff0b2734), + const Color(0xffcbced7) +]; + +const List _kBackgroundColorsBottom = const [ + const Color(0xff4aaafb), + const Color(0xff4c5471), + const Color(0xffe0e3ec) +]; + +class WeatherWorld extends NodeWithSize { + WeatherWorld() : super(const Size(2048.0, 2048.0)) { + _background = new GradientNode( + this.size, + _kBackgroundColorsTop[0], + _kBackgroundColorsBottom[0] + ); + addChild(_background); + + _cloudsSharp = new CloudLayer( + image: _images['packages/flutter_gallery_assets/clouds-0.png'], + rotated: false, + dark: false, + loopTime: 20.0 + ); + addChild(_cloudsSharp); + + _cloudsDark = new CloudLayer( + image: _images['packages/flutter_gallery_assets/clouds-1.png'], + rotated: true, + dark: true, + loopTime: 40.0 + ); + addChild(_cloudsDark); + + _cloudsSoft = new CloudLayer( + image: _images['packages/flutter_gallery_assets/clouds-1.png'], + rotated: false, + dark: false, + loopTime: 60.0 + ); + addChild(_cloudsSoft); + + _sun = new Sun(); + _sun.position = const Point(1024.0, 1024.0); + _sun.scale = 1.5; + addChild(_sun); + + _rain = new Rain(); + addChild(_rain); + + _snow = new Snow(); + addChild(_snow); + } + + GradientNode _background; + CloudLayer _cloudsSharp; + CloudLayer _cloudsSoft; + CloudLayer _cloudsDark; + Sun _sun; + Rain _rain; + Snow _snow; + + WeatherType get weatherType => _weatherType; + + WeatherType _weatherType = WeatherType.sun; + + void set weatherType(WeatherType weatherType) { + if (weatherType == _weatherType) + return; + + _weatherType = weatherType; + + // Fade the background + _background.actions.stopAll(); + + _background.actions.run(new ActionTween( + (Color a) => _background.colorTop = a, + _background.colorTop, + _kBackgroundColorsTop[weatherType.index], + 1.0 + )); + + _background.actions.run(new ActionTween( + (Color a) => _background.colorBottom = a, + _background.colorBottom, + _kBackgroundColorsBottom[weatherType.index], + 1.0 + )); + + _cloudsDark.active = weatherType != WeatherType.sun; + _sun.active = weatherType == WeatherType.sun; + _rain.active = weatherType == WeatherType.rain; + _snow.active = weatherType == WeatherType.snow; + } + + @override + void spriteBoxPerformedLayout() { + _sun.position = spriteBox.visibleArea.topLeft + const Offset(350.0, 180.0); + } +} + +class GradientNode extends NodeWithSize { + GradientNode(Size size, this.colorTop, this.colorBottom) : super(size); + + Color colorTop; + Color colorBottom; + + @override + void paint(Canvas canvas) { + applyTransformForPivot(canvas); + + Rect rect = Point.origin & size; + Paint gradientPaint = new Paint()..shader = new LinearGradient( + begin: FractionalOffset.topLeft, + end: FractionalOffset.bottomLeft, + colors: [colorTop, colorBottom], + stops: [0.0, 1.0] + ).createShader(rect); + + canvas.drawRect(rect, gradientPaint); + } +} + +class CloudLayer extends Node { + CloudLayer({ ui.Image image, bool dark, bool rotated, double loopTime }) { + _sprites.add(_createSprite(image, dark, rotated)); + _sprites[0].position = const Point(1024.0, 1024.0); + addChild(_sprites[0]); + + _sprites.add(_createSprite(image, dark, rotated)); + _sprites[1].position = const Point(3072.0, 1024.0); + addChild(_sprites[1]); + + actions.run(new ActionRepeatForever( + new ActionTween( + (Point a) => position = a, + Point.origin, + const Point(-2048.0, 0.0), + loopTime) + )); + } + + List _sprites = []; + + Sprite _createSprite(ui.Image image, bool dark, bool rotated) { + Sprite sprite = new Sprite.fromImage(image); + + if (rotated) + sprite.scaleX = -1.0; + + if (dark) { + sprite.colorOverlay = const Color(0xff000000); + sprite.opacity = 0.0; + } + + return sprite; + } + + void set active(bool active) { + double opacity; + if (active) opacity = 1.0; + else opacity = 0.0; + + for (Sprite sprite in _sprites) { + sprite.actions.stopAll(); + sprite.actions.run(new ActionTween( + (double a) => sprite.opacity = a, + sprite.opacity, + opacity, + 1.0 + )); + } + } +} + +const double _kNumSunRays = 50.0; + +class Sun extends Node { + Sun() { + _sun = new Sprite.fromImage(_images['packages/flutter_gallery_assets/sun.png']); + _sun.scale = 4.0; + _sun.transferMode = TransferMode.plus; + addChild(_sun); + + _rays = []; + for (int i = 0; i < _kNumSunRays; i += 1) { + Ray ray = new Ray(); + addChild(ray); + _rays.add(ray); + } + } + + Sprite _sun; + List _rays; + + void set active(bool active) { + actions.stopAll(); + + double targetOpacity; + if (!active) targetOpacity = 0.0; + else targetOpacity = 1.0; + + actions.run( + new ActionTween( + (double a) => _sun.opacity = a, + _sun.opacity, + targetOpacity, + 2.0 + ) + ); + + if (active) { + for (Ray ray in _rays) { + actions.run(new ActionSequence([ + new ActionDelay(1.5), + new ActionTween( + (double a) => ray.opacity = a, + ray.opacity, + ray.maxOpacity, + 1.5 + ) + ])); + } + } else { + for (Ray ray in _rays) { + actions.run(new ActionTween( + (double a) => ray.opacity = a, + ray.opacity, + 0.0, + 0.2 + )); + } + } + } +} + +class Ray extends Sprite { + double _rotationSpeed; + double maxOpacity; + + Ray() : super.fromImage(_images['packages/flutter_gallery_assets/ray.png']) { + pivot = const Point(0.0, 0.5); + transferMode = TransferMode.plus; + rotation = randomDouble() * 360.0; + maxOpacity = randomDouble() * 0.2; + opacity = maxOpacity; + scaleX = 2.5 + randomDouble(); + scaleY = 0.3; + _rotationSpeed = randomSignedDouble() * 2.0; + + // Scale animation + double scaleTime = randomSignedDouble() * 2.0 + 4.0; + + actions.run(new ActionRepeatForever( + new ActionSequence([ + new ActionTween((double a) => scaleX = a, scaleX, scaleX * 0.5, scaleTime), + new ActionTween((double a) => scaleX = a, scaleX * 0.5, scaleX, scaleTime) + ]) + )); + } + + @override + void update(double dt) { + rotation += dt * _rotationSpeed; + } +} + +class Rain extends Node { + Rain() { + _addParticles(1.0); + _addParticles(1.5); + _addParticles(2.0); + } + + List _particles = []; + + void _addParticles(double distance) { + ParticleSystem particles = new ParticleSystem( + _sprites['raindrop.png'], + transferMode: TransferMode.srcATop, + posVar: const Point(1300.0, 0.0), + direction: 90.0, + directionVar: 0.0, + speed: 1000.0 / distance, + speedVar: 100.0 / distance, + startSize: 1.2 / distance, + startSizeVar: 0.2 / distance, + endSize: 1.2 / distance, + endSizeVar: 0.2 / distance, + life: 1.5 * distance, + lifeVar: 1.0 * distance + ); + particles.position = const Point(1024.0, -200.0); + particles.rotation = 10.0; + particles.opacity = 0.0; + + _particles.add(particles); + addChild(particles); + } + + void set active(bool active) { + actions.stopAll(); + for (ParticleSystem system in _particles) { + if (active) { + actions.run( + new ActionTween( + (double a) => system.opacity = a, + system.opacity, + 1.0, + 2.0 + )); + } else { + actions.run( + new ActionTween( + (double a) => system.opacity = a, + system.opacity, + 0.0, + 0.5 + )); + } + } + } +} + +class Snow extends Node { + Snow() { + _addParticles(_sprites['flake-0.png'], 1.0); + _addParticles(_sprites['flake-1.png'], 1.0); + _addParticles(_sprites['flake-2.png'], 1.0); + + _addParticles(_sprites['flake-3.png'], 1.5); + _addParticles(_sprites['flake-4.png'], 1.5); + _addParticles(_sprites['flake-5.png'], 1.5); + + _addParticles(_sprites['flake-6.png'], 2.0); + _addParticles(_sprites['flake-7.png'], 2.0); + _addParticles(_sprites['flake-8.png'], 2.0); + } + + List _particles = []; + + void _addParticles(Texture texture, double distance) { + ParticleSystem particles = new ParticleSystem( + texture, + transferMode: TransferMode.srcATop, + posVar: const Point(1300.0, 0.0), + direction: 90.0, + directionVar: 0.0, + speed: 150.0 / distance, + speedVar: 50.0 / distance, + startSize: 1.0 / distance, + startSizeVar: 0.3 / distance, + endSize: 1.2 / distance, + endSizeVar: 0.2 / distance, + life: 20.0 * distance, + lifeVar: 10.0 * distance, + emissionRate: 2.0, + startRotationVar: 360.0, + endRotationVar: 360.0, + radialAccelerationVar: 10.0 / distance, + tangentialAccelerationVar: 10.0 / distance + ); + particles.position = const Point(1024.0, -50.0); + particles.opacity = 0.0; + + _particles.add(particles); + addChild(particles); + } + + void set active(bool active) { + actions.stopAll(); + for (ParticleSystem system in _particles) { + if (active) { + actions.run( + new ActionTween((double a) => system.opacity = a, system.opacity, 1.0, 2.0 + )); + } else { + actions.run( + new ActionTween((double a) => system.opacity = a, system.opacity, 0.0, 0.5 + )); + } + } + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/app.dart b/examples/flutter_gallery/material_gallery/lib/gallery/app.dart new file mode 100644 index 0000000000..10b8758a9b --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/app.dart @@ -0,0 +1,85 @@ +// Copyright 2015 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' show timeDilation; + +import '../demo/all.dart'; +import 'home.dart'; + +final Map kRoutes = { + WeatherDemo.routeName: (BuildContext context) => new WeatherDemo(), + FitnessDemo.routeName: (BuildContext context) => new FitnessDemo(), + DrawingDemo.routeName: (BuildContext context) => new DrawingDemo(), + FlexibleSpaceDemo.routeName: (BuildContext context) => new FlexibleSpaceDemo(), + TabsFabDemo.routeName: (BuildContext context) => new TabsFabDemo(), + ButtonsDemo.routeName: (BuildContext context) => new ButtonsDemo(), + CardsDemo.routeName: (BuildContext context) => new CardsDemo(), + ChipDemo.routeName: (BuildContext context) => new ChipDemo(), + DatePickerDemo.routeName: (BuildContext context) => new DatePickerDemo(), + DataTableDemo.routeName: (BuildContext context) => new DataTableDemo(), + DialogDemo.routeName: (BuildContext context) => new DialogDemo(), + DropDownDemo.routeName: (BuildContext context) => new DropDownDemo(), + TwoLevelListDemo.routeName: (BuildContext context) => new TwoLevelListDemo(), + GridListDemo.routeName: (BuildContext context) => new GridListDemo(), + IconsDemo.routeName: (BuildContext context) => new IconsDemo(), + LeaveBehindDemo.routeName: (BuildContext context) => new LeaveBehindDemo(), + ListDemo.routeName: (BuildContext context) => new ListDemo(), + MenuDemo.routeName: (BuildContext context) => new MenuDemo(), + ModalBottomSheetDemo.routeName: (BuildContext context) => new ModalBottomSheetDemo(), + OverscrollDemo.routeName: (BuildContext context) => new OverscrollDemo(), + PageSelectorDemo.routeName: (BuildContext context) => new PageSelectorDemo(), + PersistentBottomSheetDemo.routeName: (BuildContext context) => new PersistentBottomSheetDemo(), + ProgressIndicatorDemo.routeName: (BuildContext context) => new ProgressIndicatorDemo(), + ScrollableTabsDemo.routeName: (BuildContext context) => new ScrollableTabsDemo(), + SelectionControlsDemo.routeName: (BuildContext context) => new SelectionControlsDemo(), + SliderDemo.routeName: (BuildContext context) => new SliderDemo(), + SnackBarDemo.routeName: (BuildContext context) => new SnackBarDemo(), + TabsDemo.routeName: (BuildContext context) => new TabsDemo(), + TextFieldDemo.routeName: (BuildContext context) => new TextFieldDemo(), + TimePickerDemo.routeName: (BuildContext context) => new TimePickerDemo(), + TooltipDemo.routeName: (BuildContext context) => new TooltipDemo(), + ColorsDemo.routeName: (BuildContext context) => new ColorsDemo(), + TypographyDemo.routeName: (BuildContext context) => new TypographyDemo(), +}; + +final ThemeData _kGalleryLightTheme = new ThemeData( + brightness: ThemeBrightness.light, + primarySwatch: Colors.purple +); + +final ThemeData _kGalleryDarkTheme = new ThemeData( + brightness: ThemeBrightness.dark, + primarySwatch: Colors.purple +); + +class GalleryApp extends StatefulWidget { + GalleryApp({ Key key }) : super(key: key); + + @override + GalleryAppState createState() => new GalleryAppState(); +} + +class GalleryAppState extends State { + bool _useLightTheme = true; + bool _showPerformanceOverlay = false; + + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Flutter Gallery', + theme: _useLightTheme ? _kGalleryLightTheme : _kGalleryDarkTheme, + showPerformanceOverlay: _showPerformanceOverlay, + routes: kRoutes, + home: new GalleryHome( + useLightTheme: _useLightTheme, + onThemeChanged: (bool value) { setState(() { _useLightTheme = value; }); }, + showPerformanceOverlay: _showPerformanceOverlay, + onShowPerformanceOverlayChanged: (bool value) { setState(() { _showPerformanceOverlay = value; }); }, + timeDilation: timeDilation, + onTimeDilationChanged: (double value) { setState(() { timeDilation = value; }); } + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/demo.dart b/examples/flutter_gallery/material_gallery/lib/gallery/demo.dart new file mode 100644 index 0000000000..5ce8e0fad5 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/demo.dart @@ -0,0 +1,278 @@ +// Copyright 2016 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_markdown/flutter_markdown.dart'; + +import 'example_code_parser.dart'; +import 'syntax_highlighter.dart'; + +class SingleComponentDemoData { + SingleComponentDemoData({ + this.widget, + this.exampleCodeTag, + this.description, + this.onPressedDemo + }); + + final Widget widget; + final String exampleCodeTag; + final String description; + final VoidCallback onPressedDemo; +} + +class ComponentDemoTabData extends SingleComponentDemoData { + ComponentDemoTabData({ + Widget widget, + String exampleCodeTag, + String description, + VoidCallback onPressedDemo, + this.tabName + }) : super( + widget: widget, + exampleCodeTag: exampleCodeTag, + description: description, + onPressedDemo: onPressedDemo + ); + + final String tabName; + + static Map buildTabLabels(List demos) { + return new Map.fromIterable( + demos, + value: (ComponentDemoTabData demo) => new TabLabel(text: demo.tabName) + ); + } + + @override + bool operator==(Object other) { + if (other.runtimeType != runtimeType) + return false; + ComponentDemoTabData typedOther = other; + return typedOther.tabName == tabName && typedOther.description == description; + } + + @override + int get hashCode => hashValues(tabName.hashCode, description.hashCode); +} + +class TabbedComponentDemoScaffold extends StatelessWidget { + TabbedComponentDemoScaffold({ + this.title, + this.demos + }); + + final List demos; + final String title; + + @override + Widget build(BuildContext context) { + return new TabBarSelection( + values: demos, + child: new Scaffold( + appBar: new AppBar( + title: new Text(title), + tabBar: new TabBar( + isScrollable: true, + labels: ComponentDemoTabData.buildTabLabels(demos) + ) + ), + body: new TabbedComponentDemo(demos) + ) + ); + } +} + +class TabbedComponentDemo extends StatelessWidget { + TabbedComponentDemo(this.demos); + + final List demos; + + @override + Widget build(BuildContext context) { + return new TabBarView( + children: demos.map(buildTabView).toList() + ); + } + + Widget buildTabView(ComponentDemoTabData demo) { + return new SingleComponentDemo(demo); + } +} + +class SingleComponentDemo extends StatelessWidget { + SingleComponentDemo(this.demo); + + final SingleComponentDemoData demo; + + @override + Widget build(BuildContext context) { + return new Column( + children: [ + new Padding( + padding: new EdgeInsets.all(16.0), + child: new MarkdownBody(data: demo.description) + ), + new Flexible( + child: demo.widget + ), + new DemoBottomBar( + exampleCodeTag: demo.exampleCodeTag, + onPressedDemo: demo.onPressedDemo + ) + ] + ); + } +} + +class DemoBottomBar extends StatelessWidget { + DemoBottomBar({ this.exampleCodeTag, this.onPressedDemo }); + + final String exampleCodeTag; + final VoidCallback onPressedDemo; + + @override + Widget build(BuildContext context) { + VoidCallback onPressedCode; + if (exampleCodeTag != null) { + onPressedCode = () { + Navigator.push(context, new MaterialPageRoute( + builder: (BuildContext context) => new FullScreenCodeDialog(exampleCodeTag: exampleCodeTag) + )); + }; + } + + return new Column( + children: [ + new Divider( + height: 1.0 + ), + new Container( + height: 48.0, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new FlatButton( + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.only(right: 8.0), + child: new Icon(icon: Icons.code) + ), + new Text('VIEW CODE') + ] + ), + onPressed: onPressedCode + ), + new FlatButton( + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.only(right: 8.0), + child: new Icon(icon: Icons.star) + ), + new Text('LIVE DEMO') + ] + ), + onPressed: onPressedDemo + ) + ] + ) + ) + ] + ); + } +} + +class FormattedCode extends StatefulWidget { + FormattedCode(this.exampleCode); + + final String exampleCode; + + @override + _FormattedCodeState createState() => new _FormattedCodeState(); +} + +class _FormattedCodeState extends State { + @override + void initState() { + super.initState(); + _formatText(); + } + + TextSpan _formattedText; + + @override + Widget build(BuildContext context) { + return new RichText(text: _formattedText); + } + + @override + void didUpdateConfig(FormattedCode oldConfig) { + super.didUpdateConfig(oldConfig); + + if (oldConfig.exampleCode != config.exampleCode) + _formatText(); + } + + void _formatText() { + _formattedText = new TextSpan( + style: new TextStyle(fontFamily: 'monospace', fontSize: 10.0), + children: [new DartSyntaxHighlighter().format(config.exampleCode)] + ); + } +} + +class FullScreenCodeDialog extends StatefulWidget { + FullScreenCodeDialog({ this.exampleCodeTag }); + + final String exampleCodeTag; + + @override + FullScreenCodeDialogState createState() => new FullScreenCodeDialogState(); +} + +class FullScreenCodeDialogState extends State { + + String _exampleCode; + + @override + void initState() { + super.initState(); + + getExampleCode(config.exampleCodeTag, DefaultAssetBundle.of(context)).then((String code) { + setState(() { + _exampleCode = code; + }); + }); + } + + @override + Widget build(BuildContext context) { + Widget body; + if (_exampleCode == null) { + body = new Center( + child: new CircularProgressIndicator() + ); + } else { + body = new ScrollableViewport( + child: new Padding( + padding: new EdgeInsets.all(16.0), + child: new FormattedCode(_exampleCode) + ) + ); + } + + return new Scaffold( + appBar: new AppBar( + leading: new IconButton( + icon: Icons.clear, + onPressed: () { Navigator.pop(context); } + ), + title: new Text('Example code') + ), + body: body + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/drawer.dart b/examples/flutter_gallery/material_gallery/lib/gallery/drawer.dart new file mode 100644 index 0000000000..a5acc12035 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/drawer.dart @@ -0,0 +1,99 @@ +// Copyright 2016 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'; + +class GalleryDrawer extends StatelessWidget { + GalleryDrawer({ + Key key, + this.useLightTheme, + this.onThemeChanged, + this.timeDilation, + this.onTimeDilationChanged, + this.showPerformanceOverlay, + this.onShowPerformanceOverlayChanged + }) : super(key: key) { + assert(onThemeChanged != null); + assert(onTimeDilationChanged != null); + } + + final bool useLightTheme; + final ValueChanged onThemeChanged; + + final double timeDilation; + final ValueChanged onTimeDilationChanged; + + final bool showPerformanceOverlay; + final ValueChanged onShowPerformanceOverlayChanged; + + @override + Widget build(BuildContext context) { + return new Drawer( + child: new Block( + children: [ + new DrawerHeader(child: new Text('Flutter gallery')), + new DrawerItem( + icon: Icons.brightness_5, + onPressed: () { onThemeChanged(true); }, + selected: useLightTheme, + child: new Row( + children: [ + new Flexible(child: new Text('Light')), + new Radio( + value: true, + groupValue: useLightTheme, + onChanged: onThemeChanged + ) + ] + ) + ), + new DrawerItem( + icon: Icons.brightness_7, + onPressed: () { onThemeChanged(false); }, + selected: useLightTheme, + child: new Row( + children: [ + new Flexible(child: new Text('Dark')), + new Radio( + value: false, + groupValue: useLightTheme, + onChanged: onThemeChanged + ) + ] + ) + ), + new Divider(), + new DrawerItem( + icon: Icons.hourglass_empty, + selected: timeDilation != 1.0, + onPressed: () { onTimeDilationChanged(timeDilation != 1.0 ? 1.0 : 20.0); }, + child: new Row( + children: [ + new Flexible(child: new Text('Animate Slowly')), + new Checkbox( + value: timeDilation != 1.0, + onChanged: (bool value) { onTimeDilationChanged(value ? 20.0 : 1.0); } + ) + ] + ) + ), + new DrawerItem( + icon: Icons.assessment, + onPressed: () { onShowPerformanceOverlayChanged(!showPerformanceOverlay); }, + selected: showPerformanceOverlay, + child: new Row( + children: [ + new Flexible(child: new Text('Performance Overlay')), + new Checkbox( + value: showPerformanceOverlay, + onChanged: (bool value) { onShowPerformanceOverlayChanged(!showPerformanceOverlay); } + ) + ] + ) + ), + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/example_code.dart b/examples/flutter_gallery/material_gallery/lib/gallery/example_code.dart new file mode 100644 index 0000000000..f444059449 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/example_code.dart @@ -0,0 +1,230 @@ +// Copyright 2016 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. + +// Note: This code is not runnable, it contains code snippets displayed in the +// gallery. + +import 'package:flutter/material.dart'; + +class ButtonsDemo { + void setState(VoidCallback callback) { } + BuildContext context; + + void buttons() { + +// START buttons_raised +// Create a raised button. +new RaisedButton( + child: new Text('BUTTON TITLE'), + onPressed: () { + // Perform some action + } +); + +// Create a disabled button. +// Buttons are disabled when onPressed isn't +// specified or is null. +new RaisedButton( + child: new Text('BUTTON TITLE') +); +// END + + +// START buttons_flat +// Create a flat button. +new FlatButton( + child: new Text('BUTTON TITLE'), + onPressed: () { + // Perform some action + } +); + +// Create a disabled button. +// Buttons are disabled when onPressed isn't +// specified or is null. +new FlatButton( + child: new Text('BUTTON TITLE') +); +// END + + +// START buttons_dropdown +// Member variable holding value. +String dropdownValue; + +// Drop down button with string values. +new DropDownButton( + value: dropdownValue, + onChanged: (String newValue) { + // null indicates the user didn't select a + // new value. + setState(() { + if (newValue != null) + dropdownValue = newValue; + }); + }, + items: ['One', 'Two', 'Free', 'Four'] + .map((String value) { + return new DropDownMenuItem( + value: value, + child: new Text(value)); + }) + .toList() +); +// END + + +// START buttons_icon +// Member variable holding toggle value. +bool value; + +// Toggleable icon button. +new IconButton( + icon: Icons.thumb_up, + onPressed: () { + setState(() => value = !value); + }, + color: value ? Theme.of(context).primaryColor : null +); +// END + + +// START buttons_action +// Floating action button in Scaffold. +new Scaffold( + appBar: new AppBar( + title: new Text('Demo') + ), + floatingActionButton: new FloatingActionButton( + child: new Icon(icon: Icons.add) + ) +); +// END + } +} + + +class SelectionControls { + void setState(VoidCallback callback) { } + + void selectionControls() { + +// START selectioncontrols_checkbox +// Member variable holding the checkbox's value. +bool checkboxValue = false; + +// Create a checkbox. +new Checkbox( + value: checkboxValue, + onChanged: (bool value) { + setState(() { + checkboxValue = value; + } + ); +}); + +// Create a disabled checkbox. +// Checkboxes are disabled when onChanged isn't +// specified or null. +new Checkbox(value: false); +// END + + +// START selectioncontrols_radio +// Member variable holding value. +int radioValue = 0; + +// Method setting value. +void handleRadioValueChanged(int value) { + setState(() { + radioValue = value; + }); +} + +// Creates a set of radio buttons. +new Row( + children: [ + new Radio( + value: 0, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ), + new Radio( + value: 1, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ), + new Radio( + value: 2, + groupValue: radioValue, + onChanged: handleRadioValueChanged + ) + ] +); + +// Creates a disabled radio button. +new Radio( + value: 0, + groupValue: 0 +); +// END + + +// START selectioncontrols_switch +// Member variable holding value. +bool switchValue = false; + +// Create a switch. +new Switch( + value: switchValue, + onChanged: (bool value) { + setState(() { + switchValue = value; + } + ); +}); + +// Create a disabled switch. +// Switches are disabled when onChanged isn't +// specified or null. +new Switch(value: false); +// END + } +} + + +class GridLists { + void gridlists() { +// START gridlists +// Creates a scrollable grid list with images +// loaded from the web. +new ScrollableGrid( + delegate: new FixedColumnCountGridDelegate( + columnCount: 3, + tileAspectRatio: 1.0, + padding: const EdgeInsets.all(4.0), + columnSpacing: 4.0, + rowSpacing: 4.0 + ), + children: [ + 'https://example.com/image-0.jpg', + 'https://example.com/image-1.jpg', + 'https://example.com/image-2.jpg', + '...', + 'https://example.com/image-n.jpg' + ].map((String url) { + return new GridTile( + footer: new GridTileBar( + title: new Text(url) + ), + child: new NetworkImage( + src: url, + fit: ImageFit.cover + ) + ); + }) +); +// END + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/example_code_parser.dart b/examples/flutter_gallery/material_gallery/lib/gallery/example_code_parser.dart new file mode 100644 index 0000000000..2cf0bff1c8 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/example_code_parser.dart @@ -0,0 +1,52 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter/services.dart'; + +const String _kStartTag = '// START '; +const String _kEndTag = '// END'; + +Map _exampleCode; + +Future getExampleCode(String tag, AssetBundle bundle) async { + if (_exampleCode == null) + await _parseExampleCode(bundle); + return _exampleCode[tag]; +} + +Future _parseExampleCode(AssetBundle bundle) async { + final String code = await bundle.loadString('lib/gallery/example_code.dart'); + _exampleCode = {}; + + final List lines = code.split('\n'); + + List codeBlock; + String codeTag; + + for (String line in lines) { + if (codeBlock == null) { + // Outside a block. + if (line.startsWith(_kStartTag)) { + // Starting a new code block. + codeBlock = []; + codeTag = line.substring(_kStartTag.length); + } else { + // Just skipping the line. + } + } else { + // Inside a block. + if (line.startsWith(_kEndTag)) { + // Add the block. + _exampleCode[codeTag] = codeBlock.join('\n'); + codeBlock = null; + codeTag = null; + } else { + // Add to the current block + codeBlock.add(line); + } + } + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/header.dart b/examples/flutter_gallery/material_gallery/lib/gallery/header.dart new file mode 100644 index 0000000000..a69008f003 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/header.dart @@ -0,0 +1,198 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_sprites/flutter_sprites.dart'; + +class GalleryHeader extends StatefulWidget { + @override + _GalleryHeaderState createState() => new _GalleryHeaderState(); +} + +class _GalleryHeaderState extends State { + _FlutterHeaderNode _headerNode; + ImageMap _images; + + Future _loadAssets() async { + final AssetBundle bundle = DefaultAssetBundle.of(context); + _images = new ImageMap(bundle); + await _images.load([ + 'packages/flutter_gallery_assets/grain.png', + 'packages/flutter_gallery_assets/shadow.png', + ]); + } + + @override + void initState() { + super.initState(); + _loadAssets().then((_) { + setState(() { + _headerNode = new _FlutterHeaderNode(_images); + }); + }); + } + + @override + Widget build(BuildContext context) { + return _headerNode == null ? new Container() : new SpriteWidget(_headerNode); + } +} + +const Size _kCanvasSize = const Size(1024.0, 1024.0); +const Point _kCenterPoint = const Point(512.0, 512.0); + +class _FlutterHeaderNode extends NodeWithSize { + _FlutterHeaderNode(this._images) : super(_kCanvasSize) { + clippingLayer.opacity = 0.0; + clippingLayer.actions.run(new ActionTween((double a) => clippingLayer.opacity = a, 0.0, 1.0, 0.5)); + addChild(clippingLayer); + + clippingLayer.addChild(new _BackgroundBox()); + + paperAnimation = new _PaperAnimation(_images); + paperAnimation.position = _kCenterPoint; + clippingLayer.addChild(paperAnimation); + + final Sprite grain = new Sprite.fromImage(_images['packages/flutter_gallery_assets/grain.png']) + ..position = _kCenterPoint; + clippingLayer.addChild(grain); + + userInteractionEnabled = true; + } + + final ImageMap _images; + final Layer clippingLayer = new Layer(); + _PaperAnimation paperAnimation; + + @override + void spriteBoxPerformedLayout() { + clippingLayer.layerRect = spriteBox.visibleArea; + } +} + +final List<_PaperConfig> _kPaperConfigs = <_PaperConfig>[ + new _PaperConfig( + color: Colors.deepPurple[500], + startPosition: const Point(-300.0, -300.0), + startRotation: -10.0, + rotationSpeed: -1.0, + parallaxDepth: 0.0, + rect: new Rect.fromLTRB(-1024.0, -280.0, 1024.0, 280.0) + ), + new _PaperConfig( + color: Colors.purple[400], + startPosition: const Point(550.0, 0.0), + startRotation: 45.0, + rotationSpeed: 0.7, + parallaxDepth: 1.0, + rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0) + ), + new _PaperConfig( + color: Colors.purple[600], + startPosition: const Point(550.0, 0.0), + startRotation: 55.0, + rotationSpeed: 0.9, + parallaxDepth: 2.0, + rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0) + ), + new _PaperConfig( + color: Colors.purple[700], + startPosition: const Point(550.0, 0.0), + startRotation: 65.0, + rotationSpeed: 1.1, + parallaxDepth: 3.0, + rect: new Rect.fromLTRB(-512.0, -512.0, 512.0, 512.0) + ) +]; + +class _PaperAnimation extends Node { + _PaperAnimation(ImageMap images) { + for (_PaperConfig config in _kPaperConfigs) { + + final _PaperSheet sheet = new _PaperSheet(config); + final _PaperSheetShadow shadow = new _PaperSheetShadow(config, images); + + addChild(shadow); + addChild(sheet); + _sheets.add(sheet); + + shadow.constraints = [ + new ConstraintRotationToNodeRotation(sheet), + new ConstraintPositionToNode(sheet, offset: const Offset(0.0, 8.0)) + ]; + } + } + + final List<_PaperSheet> _sheets = <_PaperSheet>[]; +} + +class _PaperConfig { + _PaperConfig({ + this.color, + this.startPosition, + this.startRotation, + this.rotationSpeed, + this.parallaxDepth, + this.rect + }); + + final Color color; + final Point startPosition; + final double startRotation; + final double rotationSpeed; + final double parallaxDepth; + final Rect rect; +} + +class _PaperSheet extends Node { + _PaperSheet(this._config) { + _paperPaint.color = _config.color; + + position = _config.startPosition; + rotation = _config.startRotation; + } + + final _PaperConfig _config; + final Paint _paperPaint = new Paint(); + + @override + void paint(Canvas canvas) { + canvas.drawRect(_config.rect, _paperPaint); + } + + @override + void update(double dt) { + rotation += _config.rotationSpeed * dt; + } +} + +class _PaperSheetShadow extends Node { + _PaperSheetShadow(this._config, ImageMap images) { + NineSliceSprite shadow = new NineSliceSprite.fromImage( + images['packages/flutter_gallery_assets/shadow.png'], + new Size( + _config.rect.size.width + 32.0, + _config.rect.size.height + 32.0 + ), + const EdgeInsets.all(0.375) + ); + shadow.drawCenterPart = false; + shadow.opacity = 0.5; + addChild(shadow); + } + + final _PaperConfig _config; +} + +class _BackgroundBox extends Node { + final Paint _boxPaint = new Paint()..color = Colors.purple[500]; + + @override + void paint(Canvas canvas) { + canvas.drawRect(new Rect.fromLTWH(0.0, 0.0, _kCanvasSize.width, _kCanvasSize.height), _boxPaint); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/home.dart b/examples/flutter_gallery/material_gallery/lib/gallery/home.dart new file mode 100644 index 0000000000..d825a193b6 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/home.dart @@ -0,0 +1,127 @@ +// Copyright 2016 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/widgets.dart'; + +import '../demo/all.dart'; +import 'drawer.dart'; +import 'header.dart'; +import 'item.dart'; + +const double _kFlexibleSpaceMaxHeight = 256.0; + +class GalleryHome extends StatefulWidget { + GalleryHome({ + Key key, + this.useLightTheme, + this.onThemeChanged, + this.timeDilation, + this.onTimeDilationChanged, + this.showPerformanceOverlay, + this.onShowPerformanceOverlayChanged + }) : super(key: key) { + assert(onThemeChanged != null); + assert(onTimeDilationChanged != null); + assert(onShowPerformanceOverlayChanged != null); + } + + final bool useLightTheme; + final ValueChanged onThemeChanged; + + final double timeDilation; + final ValueChanged onTimeDilationChanged; + + final bool showPerformanceOverlay; + final ValueChanged onShowPerformanceOverlayChanged; + + @override + GalleryHomeState createState() => new GalleryHomeState(); +} + +class GalleryHomeState extends State { + final Key _homeKey = new ValueKey("Gallery Home"); + + @override + Widget build(BuildContext context) { + final double statusBarHight = (MediaQuery.of(context)?.padding ?? EdgeInsets.zero).top; + + return new Scaffold( + key: _homeKey, + drawer: new GalleryDrawer( + useLightTheme: config.useLightTheme, + onThemeChanged: config.onThemeChanged, + timeDilation: config.timeDilation, + onTimeDilationChanged: config.onTimeDilationChanged, + showPerformanceOverlay: config.showPerformanceOverlay, + onShowPerformanceOverlayChanged: config.onShowPerformanceOverlayChanged + ), + appBar: new AppBar( + expandedHeight: _kFlexibleSpaceMaxHeight, + flexibleSpace: new FlexibleSpaceBar( + title: new Text('Flutter gallery'), + background: new GalleryHeader() + ) + ), + appBarBehavior: AppBarBehavior.under, + body: new TwoLevelList( + padding: new EdgeInsets.only(top: _kFlexibleSpaceMaxHeight + statusBarHight), + type: MaterialListType.oneLine, + children: [ + new TwoLevelSublist( + leading: new Icon(icon: Icons.star), + title: new Text('Demos'), + children: [ + new GalleryItem(title: 'Weather', routeName: WeatherDemo.routeName), + new GalleryItem(title: 'Fitness', routeName: FitnessDemo.routeName), + new GalleryItem(title: 'Fancy lines', routeName: DrawingDemo.routeName), + new GalleryItem(title: 'Flexible space toolbar', routeName: FlexibleSpaceDemo.routeName), + new GalleryItem(title: 'Floating action button', routeName: TabsFabDemo.routeName), + ] + ), + new TwoLevelSublist( + leading: new Icon(icon: Icons.extension), + title: new Text('Components'), + children: [ + new GalleryItem(title: 'Buttons', routeName: ButtonsDemo.routeName), + new GalleryItem(title: 'Cards', routeName: CardsDemo.routeName), + new GalleryItem(title: 'Chips', routeName: ChipDemo.routeName), + new GalleryItem(title: 'Date picker', routeName: DatePickerDemo.routeName), + new GalleryItem(title: 'Data tables', routeName: DataTableDemo.routeName), + new GalleryItem(title: 'Dialog', routeName: DialogDemo.routeName), + new GalleryItem(title: 'Drop-down button', routeName: DropDownDemo.routeName), + new GalleryItem(title: 'Expand/collapse list control', routeName: TwoLevelListDemo.routeName), + new GalleryItem(title: 'Grid', routeName: GridListDemo.routeName), + new GalleryItem(title: 'Icons', routeName: IconsDemo.routeName), + new GalleryItem(title: 'Leave-behind list items', routeName: LeaveBehindDemo.routeName), + new GalleryItem(title: 'List', routeName: ListDemo.routeName), + new GalleryItem(title: 'Menus', routeName: MenuDemo.routeName), + new GalleryItem(title: 'Modal bottom sheet', routeName: ModalBottomSheetDemo.routeName), + new GalleryItem(title: 'Over-scroll', routeName: OverscrollDemo.routeName), + new GalleryItem(title: 'Page selector', routeName: PageSelectorDemo.routeName), + new GalleryItem(title: 'Persistent bottom sheet', routeName: PersistentBottomSheetDemo.routeName), + new GalleryItem(title: 'Progress indicators', routeName: ProgressIndicatorDemo.routeName), + new GalleryItem(title: 'Scrollable tabs', routeName: ScrollableTabsDemo.routeName), + new GalleryItem(title: 'Selection controls', routeName: SelectionControlsDemo.routeName), + new GalleryItem(title: 'Sliders', routeName: SliderDemo.routeName), + new GalleryItem(title: 'Snackbar', routeName: SnackBarDemo.routeName), + new GalleryItem(title: 'Tabs', routeName: TabsDemo.routeName), + new GalleryItem(title: 'Text fields', routeName: TextFieldDemo.routeName), + new GalleryItem(title: 'Time picker', routeName: TimePickerDemo.routeName), + new GalleryItem(title: 'Tooltips', routeName: TooltipDemo.routeName), + ] + ), + new TwoLevelSublist( + leading: new Icon(icon: Icons.color_lens), + title: new Text('Style'), + children: [ + new GalleryItem(title: 'Colors', routeName: ColorsDemo.routeName), + new GalleryItem(title: 'Typography', routeName: TypographyDemo.routeName), + ] + ) + ] + ) + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/item.dart b/examples/flutter_gallery/material_gallery/lib/gallery/item.dart new file mode 100644 index 0000000000..06b3326647 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/item.dart @@ -0,0 +1,36 @@ +// Copyright 2016 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 'dart:developer'; + +import 'package:flutter/material.dart'; + +typedef Widget GalleryDemoBuilder(); + +class GalleryItem extends StatelessWidget { + GalleryItem({ this.title, this.icon, this.routeName }); + + final String title; + final IconData icon; + final String routeName; + + @override + Widget build(BuildContext context) { + Widget leading = icon == null ? new Container() : new Icon(icon: icon); + + return new TwoLevelListItem( + leading: leading, + title: new Text(title), + onTap: () { + if (routeName != null) { + Timeline.instantSync('Start Transition', arguments: { + 'from': '/', + 'to': routeName + }); + Navigator.pushNamed(context, routeName); + } + } + ); + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/gallery/syntax_highlighter.dart b/examples/flutter_gallery/material_gallery/lib/gallery/syntax_highlighter.dart new file mode 100644 index 0000000000..0a7190cbc3 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/gallery/syntax_highlighter.dart @@ -0,0 +1,345 @@ +// Copyright 2016 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:string_scanner/string_scanner.dart'; + +class SyntaxHighlighterStyle { + SyntaxHighlighterStyle({ + this.baseStyle, + this.numberStyle, + this.commentStyle, + this.keywordStyle, + this.stringStyle, + this.punctuationStyle, + this.classStyle, + this.constantStyle + }); + + static SyntaxHighlighterStyle defaultStyle() { + return new SyntaxHighlighterStyle( + baseStyle: new TextStyle(color: const Color(0xff000000)), + numberStyle: new TextStyle(color: const Color(0xFF1565C0)), + commentStyle: new TextStyle(color: const Color(0xFF9E9E9E)), + keywordStyle: new TextStyle(color: const Color(0xFF9C27B0)), + stringStyle: new TextStyle(color: const Color(0xFF43A047)), + punctuationStyle: new TextStyle(color: const Color(0xff000000)), + classStyle: new TextStyle(color: const Color(0xFF512DA8)), + constantStyle: new TextStyle(color: const Color(0xFF795548)) + ); + } + + final TextStyle baseStyle; + final TextStyle numberStyle; + final TextStyle commentStyle; + final TextStyle keywordStyle; + final TextStyle stringStyle; + final TextStyle punctuationStyle; + final TextStyle classStyle; + final TextStyle constantStyle; +} + +abstract class SyntaxHighlighter { + TextSpan format(String src); +} + +class DartSyntaxHighlighter extends SyntaxHighlighter { + DartSyntaxHighlighter([this._style]) { + _spans = <_HighlightSpan>[]; + + if (_style == null) + _style = SyntaxHighlighterStyle.defaultStyle(); + } + + SyntaxHighlighterStyle _style; + + static const List _kKeywords = const [ + 'abstract', 'as', 'assert', 'async', 'await', 'break', 'case', 'catch', + 'class', 'const', 'continue', 'default', 'deferred', 'do', 'dynamic', 'else', + 'enum', 'export', 'external', 'extends', 'factory', 'false', 'final', + 'finally', 'for', 'get', 'if', 'implements', 'import', 'in', 'is', 'library', + 'new', 'null', 'operator', 'part', 'rethrow', 'return', 'set', 'static', + 'super', 'switch', 'sync', 'this', 'throw', 'true', 'try', 'typedef', 'var', + 'void', 'while', 'with', 'yield' + ]; + + static const List _kBuiltInTypes = const [ + 'int', 'double', 'num', 'bool' + ]; + + String _src; + StringScanner _scanner; + + List<_HighlightSpan> _spans; + + @override + TextSpan format(String src) { + _src = src; + _scanner = new StringScanner(_src); + + if (_generateSpans()) { + // Successfully parsed the code + List formattedText = []; + int currentPosition = 0; + + for (_HighlightSpan span in _spans) { + if (currentPosition != span.start) + formattedText.add(new TextSpan(text: _src.substring(currentPosition, span.start))); + + formattedText.add(new TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src))); + + currentPosition = span.end; + } + + if (currentPosition != _src.length) + formattedText.add(new TextSpan(text: _src.substring(currentPosition, _src.length))); + + return new TextSpan(style: _style.baseStyle, children: formattedText); + } else { + // Parsing failed, return with only basic formatting + return new TextSpan(style:_style.baseStyle, text: src); + } + } + + bool _generateSpans() { + int lastLoopPosition = _scanner.position; + + while(!_scanner.isDone) { + // Skip White space + _scanner.scan(new RegExp(r"\s+")); + + // Block comments + if (_scanner.scan(new RegExp(r"/\*(.|\n)*\*/"))) { + _spans.add(new _HighlightSpan( + _HighlightType.comment, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Line comments + if (_scanner.scan("//")) { + int startComment = _scanner.lastMatch.start; + + bool eof = false; + int endComment; + if (_scanner.scan(new RegExp(r".*\n"))) { + endComment = _scanner.lastMatch.end - 1; + } else { + eof = true; + endComment = _src.length; + } + + _spans.add(new _HighlightSpan( + _HighlightType.comment, + startComment, + endComment + )); + + if (eof) + break; + + continue; + } + + // Raw r"String" + if (_scanner.scan(new RegExp(r'r".*"'))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Raw r'String' + if (_scanner.scan(new RegExp(r"r'.*'"))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Multiline """String""" + if (_scanner.scan(new RegExp(r'"""(?:[^"\\]|\\(.|\n))*"""'))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Multiline '''String''' + if (_scanner.scan(new RegExp(r"'''(?:[^'\\]|\\(.|\n))*'''"))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // "String" + if (_scanner.scan(new RegExp(r'"(?:[^"\\]|\\.)*"'))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // 'String' + if (_scanner.scan(new RegExp(r"'(?:[^'\\]|\\.)*'"))) { + _spans.add(new _HighlightSpan( + _HighlightType.string, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Double + if (_scanner.scan(new RegExp(r"\d+\.\d+"))) { + _spans.add(new _HighlightSpan( + _HighlightType.number, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Integer + if (_scanner.scan(new RegExp(r"\d+"))) { + _spans.add(new _HighlightSpan( + _HighlightType.number, + _scanner.lastMatch.start, + _scanner.lastMatch.end) + ); + continue; + } + + // Punctuation + if (_scanner.scan(new RegExp(r"[\[\]{}().!=<>&\|\?\+\-\*/%\^~;:,]"))) { + _spans.add(new _HighlightSpan( + _HighlightType.punctuation, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Metadata + if (_scanner.scan(new RegExp(r"@\w+"))) { + _spans.add(new _HighlightSpan( + _HighlightType.keyword, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + continue; + } + + // Words + if (_scanner.scan(new RegExp(r"\w+"))) { + _HighlightType type; + + String word = _scanner.lastMatch[0]; + if (word.startsWith("_")) + word = word.substring(1); + + if (_kKeywords.contains(word)) + type = _HighlightType.keyword; + else if (_kBuiltInTypes.contains(word)) + type = _HighlightType.keyword; + else if (_firstLetterIsUpperCase(word)) + type = _HighlightType.klass; + else if (word.length >= 2 && word.startsWith("k") && _firstLetterIsUpperCase(word.substring(1))) + type = _HighlightType.constant; + + if (type != null) { + _spans.add(new _HighlightSpan( + type, + _scanner.lastMatch.start, + _scanner.lastMatch.end + )); + } + } + + // Check if this loop did anything + if (lastLoopPosition == _scanner.position) { + // Failed to parse this file, abort gracefully + return false; + } + lastLoopPosition = _scanner.position; + } + + _simplify(); + return true; + } + + void _simplify() { + for(int i = _spans.length - 2; i >= 0; i -= 1) { + if (_spans[i].type == _spans[i + 1].type && _spans[i].end == _spans[i + 1].start) { + _spans[i] = new _HighlightSpan( + _spans[i].type, + _spans[i].start, + _spans[i + 1].end + ); + _spans.removeAt(i + 1); + } + } + } + + bool _firstLetterIsUpperCase(String str) { + if (str.length > 0) { + String first = str.substring(0, 1); + return first == first.toUpperCase(); + } + return false; + } +} + +enum _HighlightType { + number, + comment, + keyword, + string, + punctuation, + klass, + constant +} + +class _HighlightSpan { + _HighlightSpan(this.type, this.start, this.end); + final _HighlightType type; + final int start; + final int end; + + String textForSpan(String src) { + return src.substring(start, end); + } + + TextStyle textStyle(SyntaxHighlighterStyle style) { + if (type == _HighlightType.number) + return style.numberStyle; + else if (type == _HighlightType.comment) + return style.commentStyle; + else if (type == _HighlightType.keyword) + return style.keywordStyle; + else if (type == _HighlightType.string) + return style.stringStyle; + else if (type == _HighlightType.punctuation) + return style.punctuationStyle; + else if (type == _HighlightType.klass) + return style.classStyle; + else if (type == _HighlightType.constant) + return style.constantStyle; + else + return style.baseStyle; + } +} diff --git a/examples/flutter_gallery/material_gallery/lib/main.dart b/examples/flutter_gallery/material_gallery/lib/main.dart new file mode 100644 index 0000000000..92f08efb71 --- /dev/null +++ b/examples/flutter_gallery/material_gallery/lib/main.dart @@ -0,0 +1,11 @@ +// Copyright 2015 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/widgets.dart'; + +import 'gallery/app.dart'; + +void main() { + runApp(new GalleryApp()); +} diff --git a/examples/material_gallery/pubspec.yaml b/examples/flutter_gallery/material_gallery/pubspec.yaml similarity index 95% rename from examples/material_gallery/pubspec.yaml rename to examples/flutter_gallery/material_gallery/pubspec.yaml index dc9e63e478..5756ac401e 100644 --- a/examples/material_gallery/pubspec.yaml +++ b/examples/flutter_gallery/material_gallery/pubspec.yaml @@ -1,4 +1,4 @@ -name: material_gallery +name: flutter_gallery dependencies: intl: '>=0.12.4+2 <0.13.0' collection: '>=1.4.0 <2.0.0' diff --git a/examples/material_gallery/test/example_code_parser_test.dart b/examples/flutter_gallery/material_gallery/test/example_code_parser_test.dart similarity index 90% rename from examples/material_gallery/test/example_code_parser_test.dart rename to examples/flutter_gallery/material_gallery/test/example_code_parser_test.dart index ffe5d25f5e..ca4b7575e1 100644 --- a/examples/material_gallery/test/example_code_parser_test.dart +++ b/examples/flutter_gallery/material_gallery/test/example_code_parser_test.dart @@ -5,12 +5,12 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:material_gallery/gallery/example_code_parser.dart'; +import 'package:flutter_gallery/gallery/example_code_parser.dart'; import 'package:mojo/core.dart' as core; import 'package:test/test.dart'; void main() { - test('Material Gallery example code parser test', () async { + test('Flutter gallery example code parser test', () async { TestAssetBundle bundle = new TestAssetBundle(); String codeSnippet0 = await getExampleCode('test_0', bundle); diff --git a/examples/material_gallery/test/smoke_test.dart b/examples/flutter_gallery/material_gallery/test/smoke_test.dart similarity index 86% rename from examples/material_gallery/test/smoke_test.dart rename to examples/flutter_gallery/material_gallery/test/smoke_test.dart index d2ab42ec2a..f8f398f08c 100644 --- a/examples/material_gallery/test/smoke_test.dart +++ b/examples/flutter_gallery/material_gallery/test/smoke_test.dart @@ -4,9 +4,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:material_gallery/gallery/app.dart' as material_gallery_app; -import 'package:material_gallery/gallery/item.dart' as material_gallery_item; -import 'package:material_gallery/main.dart' as material_gallery_main; +import 'package:flutter_gallery/gallery/app.dart' as flutter_gallery_app; +import 'package:flutter_gallery/gallery/item.dart' as flutter_gallery_item; +import 'package:flutter_gallery/main.dart' as flutter_gallery_main; import 'package:test/test.dart'; // Warning: the following strings must be kept in sync with GalleryHome. @@ -14,7 +14,7 @@ const List demoCategories = const ['Demos', 'Components', 'Style Finder findGalleryItemByRouteName(WidgetTester tester, String routeName) { return find.byWidgetPredicate((Widget widget) { - return widget is material_gallery_item.GalleryItem + return widget is flutter_gallery_item.GalleryItem && widget.routeName == routeName; }); } @@ -50,8 +50,8 @@ void smokeDemo(WidgetTester tester, String routeName) { } void main() { - testWidgets('Material Gallery app smoke test', (WidgetTester tester) { - material_gallery_main.main(); // builds the app and schedules a frame but doesn't trigger one + testWidgets('Flutter gallery app smoke test', (WidgetTester tester) { + flutter_gallery_main.main(); // builds the app and schedules a frame but doesn't trigger one tester.pump(); // see https://github.com/flutter/flutter/issues/1865 tester.pump(); // triggers a frame @@ -64,7 +64,7 @@ void main() { final List scrollDeltas = new List(); double previousY = tester.getTopRight(find.text(demoCategories[0])).y; - final List routeNames = material_gallery_app.kRoutes.keys.toList(); + final List routeNames = flutter_gallery_app.kRoutes.keys.toList(); for (String routeName in routeNames) { final double y = tester.getTopRight(findGalleryItemByRouteName(tester, routeName)).y; scrollDeltas.add(previousY - y); diff --git a/examples/material_gallery/test_driver/scroll_perf.dart b/examples/flutter_gallery/material_gallery/test_driver/scroll_perf.dart similarity index 84% rename from examples/material_gallery/test_driver/scroll_perf.dart rename to examples/flutter_gallery/material_gallery/test_driver/scroll_perf.dart index 1b0b033f24..c0010d05b2 100644 --- a/examples/material_gallery/test_driver/scroll_perf.dart +++ b/examples/flutter_gallery/material_gallery/test_driver/scroll_perf.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'package:flutter_driver/driver_extension.dart'; -import 'package:material_gallery/main.dart' as app; +import 'package:flutter_gallery/main.dart' as app; void main() { enableFlutterDriverExtension(); diff --git a/examples/material_gallery/test_driver/scroll_perf_test.dart b/examples/flutter_gallery/material_gallery/test_driver/scroll_perf_test.dart similarity index 100% rename from examples/material_gallery/test_driver/scroll_perf_test.dart rename to examples/flutter_gallery/material_gallery/test_driver/scroll_perf_test.dart diff --git a/examples/material_gallery/test_driver/transitions_perf.dart b/examples/flutter_gallery/material_gallery/test_driver/transitions_perf.dart similarity index 84% rename from examples/material_gallery/test_driver/transitions_perf.dart rename to examples/flutter_gallery/material_gallery/test_driver/transitions_perf.dart index 1b0b033f24..c0010d05b2 100644 --- a/examples/material_gallery/test_driver/transitions_perf.dart +++ b/examples/flutter_gallery/material_gallery/test_driver/transitions_perf.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'package:flutter_driver/driver_extension.dart'; -import 'package:material_gallery/main.dart' as app; +import 'package:flutter_gallery/main.dart' as app; void main() { enableFlutterDriverExtension(); diff --git a/examples/material_gallery/test_driver/transitions_perf_test.dart b/examples/flutter_gallery/material_gallery/test_driver/transitions_perf_test.dart similarity index 100% rename from examples/material_gallery/test_driver/transitions_perf_test.dart rename to examples/flutter_gallery/material_gallery/test_driver/transitions_perf_test.dart diff --git a/examples/flutter_gallery/pubspec.yaml b/examples/flutter_gallery/pubspec.yaml new file mode 100644 index 0000000000..5756ac401e --- /dev/null +++ b/examples/flutter_gallery/pubspec.yaml @@ -0,0 +1,20 @@ +name: flutter_gallery +dependencies: + intl: '>=0.12.4+2 <0.13.0' + collection: '>=1.4.0 <2.0.0' + string_scanner: '0.1.4+1' + + flutter: + path: ../../packages/flutter + flutter_sprites: + path: ../../packages/flutter_sprites + flutter_markdown: + path: ../../packages/flutter_markdown + flutter_gallery_assets: '0.0.16' + +dev_dependencies: + test: any # flutter_test provides the version constraints + flutter_test: + path: ../../packages/flutter_test + flutter_driver: + path: ../../packages/flutter_driver diff --git a/examples/flutter_gallery/test/example_code_parser_test.dart b/examples/flutter_gallery/test/example_code_parser_test.dart new file mode 100644 index 0000000000..ca4b7575e1 --- /dev/null +++ b/examples/flutter_gallery/test/example_code_parser_test.dart @@ -0,0 +1,53 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_gallery/gallery/example_code_parser.dart'; +import 'package:mojo/core.dart' as core; +import 'package:test/test.dart'; + +void main() { + test('Flutter gallery example code parser test', () async { + TestAssetBundle bundle = new TestAssetBundle(); + + String codeSnippet0 = await getExampleCode('test_0', bundle); + expect(codeSnippet0, 'test 0 0\ntest 0 1'); + + String codeSnippet1 = await getExampleCode('test_1', bundle); + expect(codeSnippet1, 'test 1 0\ntest 1 1'); + }); +} + +const String testCodeFile = """// A fake test file +// START test_0 +test 0 0 +test 0 1 +// END + +// Some comments +// START test_1 +test 1 0 +test 1 1 +// END +"""; + +class TestAssetBundle extends AssetBundle { + @override + ImageResource loadImage(String key) => null; + + @override + Future loadString(String key) { + if (key == 'lib/gallery/example_code.dart') + return new Future.value(testCodeFile); + return null; + } + + @override + Future load(String key) => null; + + @override + String toString() => '$runtimeType@$hashCode()'; +} diff --git a/examples/flutter_gallery/test/smoke_test.dart b/examples/flutter_gallery/test/smoke_test.dart new file mode 100644 index 0000000000..f8f398f08c --- /dev/null +++ b/examples/flutter_gallery/test/smoke_test.dart @@ -0,0 +1,98 @@ +// Copyright 2016 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_test/flutter_test.dart'; +import 'package:flutter_gallery/gallery/app.dart' as flutter_gallery_app; +import 'package:flutter_gallery/gallery/item.dart' as flutter_gallery_item; +import 'package:flutter_gallery/main.dart' as flutter_gallery_main; +import 'package:test/test.dart'; + +// Warning: the following strings must be kept in sync with GalleryHome. +const List demoCategories = const ['Demos', 'Components', 'Style']; + +Finder findGalleryItemByRouteName(WidgetTester tester, String routeName) { + return find.byWidgetPredicate((Widget widget) { + return widget is flutter_gallery_item.GalleryItem + && widget.routeName == routeName; + }); +} + +Finder byTooltip(WidgetTester tester, String message) { + return find.byWidgetPredicate((Widget widget) { + return widget is Tooltip && widget.message == message; + }); +} + +Finder findNavigationMenuButton(WidgetTester tester) => byTooltip(tester, 'Open navigation menu'); + +Finder findBackButton(WidgetTester tester) => byTooltip(tester, 'Back'); + +// Start a gallery demo and then go back. This function assumes that the +// we're starting on home route and that the submenu that contains the demo +// called 'name' is already open. +void smokeDemo(WidgetTester tester, String routeName) { + // Ensure that we're (likely to be) on the home page + final Finder menuItem = findGalleryItemByRouteName(tester, routeName); + expect(menuItem, findsOneWidget); + + tester.tap(menuItem); + tester.pump(); // Launch the demo. + tester.pump(const Duration(seconds: 1)); // Wait until the demo has opened. + + // Go back + Finder backButton = findBackButton(tester); + expect(backButton, findsOneWidget); + tester.tap(backButton); + tester.pump(); // Start the navigator pop "back" operation. + tester.pump(const Duration(seconds: 1)); // Wait until it has finished. +} + +void main() { + testWidgets('Flutter gallery app smoke test', (WidgetTester tester) { + flutter_gallery_main.main(); // builds the app and schedules a frame but doesn't trigger one + tester.pump(); // see https://github.com/flutter/flutter/issues/1865 + tester.pump(); // triggers a frame + + // Expand the demo category submenus. + for (String category in demoCategories.reversed) { + tester.tap(find.text(category)); + tester.pump(); + tester.pump(const Duration(seconds: 1)); // Wait until the menu has expanded. + } + + final List scrollDeltas = new List(); + double previousY = tester.getTopRight(find.text(demoCategories[0])).y; + final List routeNames = flutter_gallery_app.kRoutes.keys.toList(); + for (String routeName in routeNames) { + final double y = tester.getTopRight(findGalleryItemByRouteName(tester, routeName)).y; + scrollDeltas.add(previousY - y); + previousY = y; + } + + // Launch each demo and then scroll that item out of the way. + for (int i = 0; i < routeNames.length; i += 1) { + final String routeName = routeNames[i]; + smokeDemo(tester, routeName); + tester.scroll(findGalleryItemByRouteName(tester, routeName), new Offset(0.0, scrollDeltas[i])); + tester.pump(); + } + + Finder navigationMenuButton = findNavigationMenuButton(tester); + expect(navigationMenuButton, findsOneWidget); + tester.tap(navigationMenuButton); + tester.pump(); // Start opening drawer. + tester.pump(const Duration(seconds: 1)); // Wait until it's really opened. + + // switch theme + tester.tap(find.text('Dark')); + tester.pump(); + tester.pump(const Duration(seconds: 1)); // Wait until it's changed. + + // switch theme + tester.tap(find.text('Light')); + tester.pump(); + tester.pump(const Duration(seconds: 1)); // Wait until it's changed. + }, skip: true); +} diff --git a/examples/flutter_gallery/test_driver/scroll_perf.dart b/examples/flutter_gallery/test_driver/scroll_perf.dart new file mode 100644 index 0000000000..c0010d05b2 --- /dev/null +++ b/examples/flutter_gallery/test_driver/scroll_perf.dart @@ -0,0 +1,11 @@ +// Copyright 2016 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_driver/driver_extension.dart'; +import 'package:flutter_gallery/main.dart' as app; + +void main() { + enableFlutterDriverExtension(); + app.main(); +} diff --git a/examples/flutter_gallery/test_driver/scroll_perf_test.dart b/examples/flutter_gallery/test_driver/scroll_perf_test.dart new file mode 100644 index 0000000000..3e57813387 --- /dev/null +++ b/examples/flutter_gallery/test_driver/scroll_perf_test.dart @@ -0,0 +1,53 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +void main() { + group('scrolling performance test', () { + FlutterDriver driver; + + setUpAll(() async { + driver = await FlutterDriver.connect(); + }); + + tearDownAll(() async { + if (driver != null) + driver.close(); + }); + + test('measure', () async { + Timeline timeline = await driver.traceAction(() async { + // Find the scrollable stock list + SerializableFinder stockList = find.byValueKey('Gallery List'); + expect(stockList, isNotNull); + + await driver.tap(find.text('Demos')); + await driver.tap(find.text('Components')); + await driver.tap(find.text('Style')); + + // TODO(eseidel): These are very artifical scrolls, we should use better + // https://github.com/flutter/flutter/issues/3316 + // Scroll down + for (int i = 0; i < 5; i++) { + await driver.scroll(stockList, 0.0, -300.0, new Duration(milliseconds: 300)); + await new Future.delayed(new Duration(milliseconds: 500)); + } + + // Scroll up + for (int i = 0; i < 5; i++) { + await driver.scroll(stockList, 0.0, 300.0, new Duration(milliseconds: 300)); + await new Future.delayed(new Duration(milliseconds: 500)); + } + }); + + new TimelineSummary.summarize(timeline) + ..writeSummaryToFile('home_scroll_perf', pretty: true) + ..writeTimelineToFile('home_scroll_perf', pretty: true); + }); + }); +} diff --git a/examples/flutter_gallery/test_driver/transitions_perf.dart b/examples/flutter_gallery/test_driver/transitions_perf.dart new file mode 100644 index 0000000000..c0010d05b2 --- /dev/null +++ b/examples/flutter_gallery/test_driver/transitions_perf.dart @@ -0,0 +1,11 @@ +// Copyright 2016 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_driver/driver_extension.dart'; +import 'package:flutter_gallery/main.dart' as app; + +void main() { + enableFlutterDriverExtension(); + app.main(); +} diff --git a/examples/flutter_gallery/test_driver/transitions_perf_test.dart b/examples/flutter_gallery/test_driver/transitions_perf_test.dart new file mode 100644 index 0000000000..96875db550 --- /dev/null +++ b/examples/flutter_gallery/test_driver/transitions_perf_test.dart @@ -0,0 +1,93 @@ +// Copyright 2016 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 'dart:async'; + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +// Warning: the following strings must be kept in sync with GalleryHome. +const List demoCategories = const ['Demos', 'Components', 'Style']; + +const List demoNames = const [ + 'Weather', + 'Fitness', + 'Fancy lines', + 'Flexible space toolbar', + 'Floating action button', + 'Buttons', + 'Cards', + 'Chips', + 'Date picker', + 'Data tables', + 'Dialog', + 'Drop-down button', + 'Expand/collapse list control', + 'Grid', + 'Icons', + 'Leave-behind list items', + 'List', + 'Menus', + 'Modal bottom sheet', + 'Over-scroll', + 'Page selector', + 'Persistent bottom sheet', + 'Progress indicators', + 'Scrollable tabs', + 'Selection controls', + 'Sliders', + 'Snackbar', + 'Tabs', + 'Text fields', + 'Time picker', + 'Tooltips', + 'Colors', + 'Typography' +]; + +void main() { + group('flutter gallery transitions', () { + FlutterDriver driver; + setUpAll(() async { + driver = await FlutterDriver.connect(); + }); + + tearDownAll(() async { + if (driver != null) + driver.close(); + }); + + test('all demos', () async { + Timeline timeline = await driver.traceAction(() async { + // Expand the demo category submenus. + for (String category in demoCategories.reversed) { + await driver.tap(find.text(category)); + await new Future.delayed(new Duration(milliseconds: 500)); + } + // Scroll each demo menu item into view, launch the demo and + // return to the demo menu 2x. + for(String demoName in demoNames) { + SerializableFinder menuItem = find.text(demoName); + await driver.scrollIntoView(menuItem); + await new Future.delayed(new Duration(milliseconds: 500)); + + for(int i = 0; i < 2; i += 1) { + await driver.tap(menuItem); // Launch the demo + await new Future.delayed(new Duration(milliseconds: 500)); + await driver.tap(find.byTooltip('Back')); + await new Future.delayed(new Duration(milliseconds: 1000)); + } + } + }, + categories: const [ + TracingCategory.dart, + TracingCategory.gc, + TracingCategory.compiler + ]); + new TimelineSummary.summarize(timeline) + ..writeSummaryToFile('transitions_perf', pretty: true) + ..writeTimelineToFile('transitions_perf', pretty: true); + }, timeout: new Timeout(new Duration(minutes: 15))); + }); +} diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart index 70c1b61059..7f8dc73686 100644 --- a/packages/flutter_tools/lib/src/commands/upgrade.dart +++ b/packages/flutter_tools/lib/src/commands/upgrade.dart @@ -70,7 +70,7 @@ class UpgradeCommand extends FlutterCommand { // rename {packages/flutter/doc => dev/docs}/styles.html (92%) // delete mode 100644 doc/index.html - // create mode 100644 examples/material_gallery/lib/gallery/demo.dart + // create mode 100644 examples/flutter_gallery/lib/gallery/demo.dart static final RegExp _gitChangedRegex = new RegExp(r' (rename|delete mode|create mode) .+'); // Public for testing. diff --git a/packages/flutter_tools/lib/src/flx.dart b/packages/flutter_tools/lib/src/flx.dart index 9f2fe39014..1144e3606f 100644 --- a/packages/flutter_tools/lib/src/flx.dart +++ b/packages/flutter_tools/lib/src/flx.dart @@ -57,7 +57,7 @@ class _Asset { bool get assetFileExists => assetFile.existsSync(); /// The delta between what the assetEntry is and the relativePath (e.g., - /// packages/material_gallery). + /// packages/flutter_gallery). String get symbolicPrefix { if (_assetEntry == null || _assetEntry == relativePath) return null; diff --git a/packages/flutter_tools/test/upgrade_test.dart b/packages/flutter_tools/test/upgrade_test.dart index 5eef614679..85c1b6e556 100644 --- a/packages/flutter_tools/test/upgrade_test.dart +++ b/packages/flutter_tools/test/upgrade_test.dart @@ -1,3 +1,4 @@ + // Copyright 2016 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. @@ -10,12 +11,12 @@ void main() { bool _match(String line) => UpgradeCommand.matchesGitLine(line); test('regex match', () { - expect(_match(' .../material_gallery/lib/demo/buttons_demo.dart | 10 +--'), true); + expect(_match(' .../flutter_gallery/lib/demo/buttons_demo.dart | 10 +--'), true); expect(_match(' dev/benchmarks/complex_layout/lib/main.dart | 24 +-'), true); expect(_match(' rename {packages/flutter/doc => dev/docs}/styles.html (92%)'), true); expect(_match(' delete mode 100644 doc/index.html'), true); - expect(_match(' create mode 100644 examples/material_gallery/lib/gallery/demo.dart'), true); + expect(_match(' create mode 100644 examples/flutter_gallery/lib/gallery/demo.dart'), true); expect(_match('Fast-forward'), true); }); diff --git a/travis/test.sh b/travis/test.sh index 1622d1adb2..38a36972b1 100755 --- a/travis/test.sh +++ b/travis/test.sh @@ -17,7 +17,7 @@ flutter analyze --flutter-repo (cd dev/manual_tests; flutter test) (cd examples/hello_world; flutter test) (cd examples/layers; flutter test) -(cd examples/material_gallery; flutter test) +(cd examples/flutter_gallery; flutter test) (cd examples/stocks; flutter test) # generate and analyze our large sample app