remove spurious copy of the material_gallery directory (#3806)
@ -1,9 +0,0 @@
|
||||
.DS_Store
|
||||
.atom/
|
||||
.idea
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
ios/.generated/
|
||||
packages
|
||||
pubspec.lock
|
@ -1,12 +0,0 @@
|
||||
# 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.
|
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.MaterialGallery" android:versionCode="1" android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application android:icon="@mipmap/ic_launcher" android:label="Flutter gallery" android:name="org.domokit.sky.shell.SkyApplication">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTop" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 10 KiB |
@ -1,41 +0,0 @@
|
||||
name: flutter_gallery
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/flutter_logo.png
|
||||
- assets/section_animation.png
|
||||
- assets/section_style.png
|
||||
- assets/section_layout.png
|
||||
- assets/section_components.png
|
||||
- assets/section_patterns.png
|
||||
- assets/section_usability.png
|
||||
- packages/flutter_gallery_assets/ali_connors.png
|
||||
- packages/flutter_gallery_assets/sun.png
|
||||
- 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.json
|
||||
- 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
|
||||
- packages/flutter_gallery_assets/kangaroo_valley_safari.png
|
||||
- packages/flutter_gallery_assets/top_10_australian_beaches.png
|
||||
- packages/flutter_gallery_assets/jumpingjack.json
|
||||
- packages/flutter_gallery_assets/jumpingjack.png
|
||||
- packages/flutter_gallery_assets/grain.png
|
||||
- packages/flutter_gallery_assets/fancylines.png
|
||||
- packages/flutter_gallery_assets/landscape_0.jpg
|
||||
- packages/flutter_gallery_assets/landscape_1.jpg
|
||||
- packages/flutter_gallery_assets/landscape_2.jpg
|
||||
- packages/flutter_gallery_assets/landscape_3.jpg
|
||||
- packages/flutter_gallery_assets/landscape_4.jpg
|
||||
- packages/flutter_gallery_assets/landscape_5.jpg
|
||||
- packages/flutter_gallery_assets/landscape_6.jpg
|
||||
- packages/flutter_gallery_assets/landscape_7.jpg
|
||||
- packages/flutter_gallery_assets/landscape_8.jpg
|
||||
- packages/flutter_gallery_assets/landscape_9.jpg
|
||||
- packages/flutter_gallery_assets/landscape_10.jpg
|
||||
- packages/flutter_gallery_assets/landscape_11.jpg
|
||||
- packages/flutter_gallery_assets/shadow.png
|
||||
- lib/gallery/example_code.dart
|
@ -1 +0,0 @@
|
||||
.generated/
|
@ -1,142 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small-40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-40.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Small-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_16x16.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_16x16@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_32x32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_32x32@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_128x128.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_128x128@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_256x256.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_256x256@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_512x512.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "icon_512x512@2x.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 869 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 425 B |
Before Width: | Height: | Size: 952 B |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 952 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 56 KiB |
@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Runner</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.materialgallery</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Flutter gallery</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
@ -1,37 +0,0 @@
|
||||
// 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';
|
@ -1,196 +0,0 @@
|
||||
// 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<ButtonsDemo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<ComponentDemoTabData> demos = <ComponentDemoTabData>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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<String>(
|
||||
value: dropdownValue,
|
||||
onChanged: (String newValue) {
|
||||
setState(() {
|
||||
if (newValue != null)
|
||||
dropdownValue = newValue;
|
||||
});
|
||||
},
|
||||
items: <String>['One', 'Two', 'Free', 'Four']
|
||||
.map((String value) {
|
||||
return new DropDownMenuItem<String>(
|
||||
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: <Widget>[
|
||||
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
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
// 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<String> description;
|
||||
|
||||
bool get isValid => assetName != null && title != null && description?.length == 3;
|
||||
}
|
||||
|
||||
final List<TravelDestination> destinations = <TravelDestination>[
|
||||
const TravelDestination(
|
||||
assetName: 'packages/flutter_gallery_assets/top_10_australian_beaches.png',
|
||||
title: 'Top 10 Australian beaches',
|
||||
description: const <String>[
|
||||
'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 <String>[
|
||||
'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: <Widget>[
|
||||
// photo and title
|
||||
new SizedBox(
|
||||
height: 184.0,
|
||||
child: new Stack(
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
// 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: <Widget>[
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// 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<ChipDemo> {
|
||||
bool _showBananas = true;
|
||||
|
||||
void _deleteBananas() {
|
||||
setState(() {
|
||||
_showBananas = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> chips = <Widget>[
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
// 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<int, Color> colors;
|
||||
final Map<int, Color> 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<ColorSwatch> colorSwatches = const <ColorSwatch>[
|
||||
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: <Widget>[
|
||||
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<Widget> 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<ColorSwatch>(
|
||||
values: colorSwatches,
|
||||
child: new Scaffold(
|
||||
appBar: new AppBar(
|
||||
elevation: 0,
|
||||
title: new Text('Colors'),
|
||||
tabBar: new TabBar<ColorSwatch>(
|
||||
isScrollable: true,
|
||||
labels: new Map<ColorSwatch, TabLabel>.fromIterable(colorSwatches, value: (ColorSwatch swatch) {
|
||||
return new TabLabel(text: swatch.name);
|
||||
})
|
||||
)
|
||||
),
|
||||
body: new TabBarView<ColorSwatch>(
|
||||
children: colorSwatches.map((ColorSwatch swatch) {
|
||||
return new ColorSwatchTabView(swatch: swatch);
|
||||
})
|
||||
.toList()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
// 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<DataTableDemo> {
|
||||
|
||||
int _sortColumnIndex;
|
||||
bool _sortAscending = true;
|
||||
|
||||
final List<Desert> _deserts = <Desert>[
|
||||
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/*<T>*/(Comparable<dynamic/*=T*/> 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<dynamic/*=T*/> aValue = getField(a);
|
||||
final Comparable<dynamic/*=T*/> 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: <Widget>[
|
||||
new Material(
|
||||
child: new IntrinsicHeight(
|
||||
child: new Block(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: <Widget>[
|
||||
new DataTable(
|
||||
sortColumnIndex: _sortColumnIndex,
|
||||
sortAscending: _sortAscending,
|
||||
columns: <DataColumn>[
|
||||
new DataColumn(
|
||||
label: new Text('Dessert (100g serving)'),
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<String>*/((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/*<num>*/((Desert d) => d.calories, columnIndex, ascending)
|
||||
),
|
||||
new DataColumn(
|
||||
label: new Text('Fat (g)'),
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<num>*/((Desert d) => d.fat, columnIndex, ascending)
|
||||
),
|
||||
new DataColumn(
|
||||
label: new Text('Carbs (g)'),
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<num>*/((Desert d) => d.carbs, columnIndex, ascending)
|
||||
),
|
||||
new DataColumn(
|
||||
label: new Text('Protein (g)'),
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<num>*/((Desert d) => d.protein, columnIndex, ascending)
|
||||
),
|
||||
new DataColumn(
|
||||
label: new Text('Sodium (mg)'),
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<num>*/((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/*<num>*/((Desert d) => d.calcium, columnIndex, ascending)
|
||||
),
|
||||
new DataColumn(
|
||||
label: new Text('Iron (%)'),
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) => _sort/*<num>*/((Desert d) => d.iron, columnIndex, ascending)
|
||||
),
|
||||
],
|
||||
rows: _deserts.map/*<DataRow>*/((Desert desert) {
|
||||
return new DataRow(
|
||||
key: new ValueKey<Desert>(desert),
|
||||
selected: desert.selected,
|
||||
onSelectChanged: (bool selected) { setState(() { desert.selected = selected; }); },
|
||||
cells: <DataCell>[
|
||||
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)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// 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<DatePickerDemo> {
|
||||
DateTime _selectedDate = new DateTime.now();
|
||||
|
||||
Future<Null> _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: <Widget>[
|
||||
new Text(new DateFormat.yMMMd().format(_selectedDate)),
|
||||
new SizedBox(height: 20.0),
|
||||
new RaisedButton(
|
||||
onPressed: _handleSelectDate,
|
||||
child: new Text('SELECT DATE')
|
||||
),
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.center
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
// 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: <Widget>[
|
||||
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<DialogDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
void showDemoDialog/*<T>*/({ BuildContext context, Dialog dialog }) {
|
||||
showDialog/*<T>*/(
|
||||
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: <Widget>[
|
||||
new RaisedButton(
|
||||
child: new Text('ALERT'),
|
||||
onPressed: () {
|
||||
showDemoDialog/*<DialogDemoAction>*/(
|
||||
context: context,
|
||||
dialog: new Dialog(
|
||||
content: new Text(
|
||||
_alertWithoutTitleText,
|
||||
style: dialogTextStyle
|
||||
),
|
||||
actions: <Widget>[
|
||||
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/*<DialogDemoAction>*/(
|
||||
context: context,
|
||||
dialog: new Dialog(
|
||||
title: new Text('Use Google\'s location service?'),
|
||||
content: new Text(
|
||||
_alertWithTitleText,
|
||||
style: dialogTextStyle
|
||||
),
|
||||
actions: <Widget>[
|
||||
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/*<String>*/(
|
||||
context: context,
|
||||
dialog: new Dialog(
|
||||
title: new Text('Set backup account'),
|
||||
content: new Column(
|
||||
children: <Widget>[
|
||||
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<DismissDialogAction>(
|
||||
builder: (BuildContext context) => new FullScreenDialogDemo()
|
||||
));
|
||||
}
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
// 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<DrawingDemo> {
|
||||
_LineDrawingNode _rootNode;
|
||||
ImageMap _images;
|
||||
|
||||
Future<Null> _loadAssets(AssetBundle bundle) async {
|
||||
_images = new ImageMap(bundle);
|
||||
await _images.load(<String>[
|
||||
'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;
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
// 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<DropDownDemo> {
|
||||
String _value = "Free";
|
||||
|
||||
List<DropDownMenuItem<String>> buildItems() {
|
||||
return <String>["One", "Two", "Free", "Four"].map((String value) {
|
||||
return new DropDownMenuItem<String>(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<String>(
|
||||
items: buildItems(),
|
||||
value: _value,
|
||||
onChanged: (String newValue) {
|
||||
setState(() {
|
||||
if (newValue != null)
|
||||
_value = newValue;
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,589 +0,0 @@
|
||||
// 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<Null> _loadAssets(AssetBundle bundle) async {
|
||||
_images = new ImageMap(bundle);
|
||||
await _images.load(<String>[
|
||||
'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: <Widget>[
|
||||
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: <Widget>[
|
||||
_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: <Widget>[
|
||||
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: <Widget>[
|
||||
new _Fireworks(),
|
||||
new Dialog(
|
||||
title: new Text('Awesome workout'),
|
||||
content: new Text('You have completed $_count jumping jacks. Good going!'),
|
||||
actions: <Widget>[
|
||||
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(<Action>[
|
||||
_createPoseAction(null, 0, 0.5),
|
||||
new ActionCallFunction(_animateJumpingLoop)
|
||||
]));
|
||||
}
|
||||
|
||||
void _animateJumpingLoop() {
|
||||
actions.run(new ActionRepeatForever(
|
||||
new ActionSequence(<Action>[
|
||||
_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<double> 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<double> d0 = _dataForPose(startPose);
|
||||
List<double> d1 = _dataForPose(endPose);
|
||||
|
||||
List<ActionTween> tweens = <ActionTween>[
|
||||
_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<double> _dataForPose(int pose) {
|
||||
if (pose == null)
|
||||
return _dataForCurrentPose();
|
||||
|
||||
if (pose == 0) {
|
||||
return <double>[
|
||||
-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 <double>[
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-70.0
|
||||
];
|
||||
} else {
|
||||
return <double>[
|
||||
40.0,
|
||||
30.0,
|
||||
10.0,
|
||||
20.0,
|
||||
-20.0,
|
||||
15.0,
|
||||
40.0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
List<double> _dataForCurrentPose() {
|
||||
return <double>[
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
// 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<Widget> 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: <Widget>[
|
||||
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<String> lines;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> 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<Widget> rowChildren = <Widget>[
|
||||
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<FlexibleSpaceDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
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: <Widget>[
|
||||
new IconButton(
|
||||
icon: Icons.create,
|
||||
tooltip: 'Search',
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
content: new Text('Not supported.')
|
||||
));
|
||||
}
|
||||
),
|
||||
new PopupMenuButton<AppBarBehavior>(
|
||||
onSelected: (AppBarBehavior value) {
|
||||
setState(() {
|
||||
_appBarBehavior = value;
|
||||
});
|
||||
},
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<AppBarBehavior>>[
|
||||
new PopupMenuItem<AppBarBehavior>(
|
||||
value: AppBarBehavior.scroll,
|
||||
child: new Text('Toolbar scrolls away')
|
||||
),
|
||||
new PopupMenuItem<AppBarBehavior>(
|
||||
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: <Widget>[
|
||||
new _ContactCategory(
|
||||
icon: Icons.call,
|
||||
children: <Widget>[
|
||||
new _ContactItem(
|
||||
icon: Icons.message,
|
||||
lines: <String>[
|
||||
'(650) 555-1234',
|
||||
'Mobile'
|
||||
]
|
||||
),
|
||||
new _ContactItem(
|
||||
icon: Icons.message,
|
||||
lines: <String>[
|
||||
'(323) 555-6789',
|
||||
'Work'
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
new _ContactCategory(
|
||||
icon: Icons.email,
|
||||
children: <Widget>[
|
||||
new _ContactItem(
|
||||
lines: <String>[
|
||||
'ali_connors@example.com',
|
||||
'Personal'
|
||||
]
|
||||
),
|
||||
new _ContactItem(
|
||||
lines: <String>[
|
||||
'aliconnors@example.com',
|
||||
'Work'
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
new _ContactCategory(
|
||||
icon: Icons.location_on,
|
||||
children: <Widget>[
|
||||
new _ContactItem(
|
||||
lines: <String>[
|
||||
'2000 Main Street',
|
||||
'San Francisco, CA',
|
||||
'Home'
|
||||
]
|
||||
),
|
||||
new _ContactItem(
|
||||
lines: <String>[
|
||||
'1600 Amphitheater Parkway',
|
||||
'Mountain View, CA',
|
||||
'Work'
|
||||
]
|
||||
),
|
||||
new _ContactItem(
|
||||
lines: <String>[
|
||||
'126 Severyns Ave',
|
||||
'Mountain View, CA',
|
||||
'Jet Travel'
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
// 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<DateTime> onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
return new DefaultTextStyle(
|
||||
style: theme.textTheme.subhead,
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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<FullScreenDialogDemo> {
|
||||
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: <Widget>[
|
||||
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: <Widget> [
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget> [
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,283 +0,0 @@
|
||||
// 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<Key> mostValuableKeys = new HashSet<Key>();
|
||||
mostValuableKeys.add(photoKey);
|
||||
|
||||
Navigator.push(context, new MaterialPageRoute<Null>(
|
||||
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<GridListDemo> {
|
||||
GridDemoTileStyle tileStyle = GridDemoTileStyle.twoLine;
|
||||
|
||||
List<Photo> photos = <Photo>[
|
||||
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<PopupMenuItem<GridDemoTileStyle>> items = <PopupMenuItem<GridDemoTileStyle>>[
|
||||
new PopupMenuItem<GridDemoTileStyle>(
|
||||
value: GridDemoTileStyle.imageOnly,
|
||||
child: new Text('Image only')
|
||||
),
|
||||
new PopupMenuItem<GridDemoTileStyle>(
|
||||
value: GridDemoTileStyle.oneLine,
|
||||
child: new Text('One line')
|
||||
),
|
||||
new PopupMenuItem<GridDemoTileStyle>(
|
||||
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: <Widget>[
|
||||
new IconButton(
|
||||
icon: Icons.more_vert,
|
||||
onPressed: () { showTileStyleMenu(context); },
|
||||
tooltip: 'Show menu'
|
||||
)
|
||||
]
|
||||
),
|
||||
body: new Column(
|
||||
children: <Widget>[
|
||||
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
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
// 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<IconsDemo> {
|
||||
static final List<Map<int, Color>> iconColorSwatches = <Map<int, Color>>[
|
||||
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: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new Flexible(
|
||||
flex: 0,
|
||||
child: new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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)
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// 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> {
|
||||
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<LeaveBehindDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
DismissDirection _dismissDirection = DismissDirection.horizontal;
|
||||
List<LeaveBehindItem> leaveBehindItems;
|
||||
|
||||
void initListItems() {
|
||||
leaveBehindItems = new List<LeaveBehindItem>.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: <Widget>[
|
||||
new PopupMenuButton<LeaveBehindDemoAction>(
|
||||
onSelected: handleDemoAction,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<LeaveBehindDemoAction>>[
|
||||
new PopupMenuItem<LeaveBehindDemoAction>(
|
||||
value: LeaveBehindDemoAction.reset,
|
||||
child: new Text('Reset the list')
|
||||
),
|
||||
new PopupMenuDivider(),
|
||||
new CheckedPopupMenuItem<LeaveBehindDemoAction>(
|
||||
value: LeaveBehindDemoAction.horizontalSwipe,
|
||||
checked: _dismissDirection == DismissDirection.horizontal,
|
||||
child: new Text('Hoizontal swipe')
|
||||
),
|
||||
new CheckedPopupMenuItem<LeaveBehindDemoAction>(
|
||||
value: LeaveBehindDemoAction.leftSwipe,
|
||||
checked: _dismissDirection == DismissDirection.endToStart,
|
||||
child: new Text('Only swipe left')
|
||||
),
|
||||
new CheckedPopupMenuItem<LeaveBehindDemoAction>(
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
// 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<ListDemo> {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
PersistentBottomSheetController<Null> _bottomSheet;
|
||||
MaterialListType _itemType = MaterialListType.threeLine;
|
||||
bool _dense = false;
|
||||
bool _showAvatars = true;
|
||||
bool _showIcons = false;
|
||||
bool _showDividers = false;
|
||||
bool _reverseSort = false;
|
||||
List<String> items = <String>[
|
||||
'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: <Widget>[
|
||||
new ListItem(
|
||||
dense: true,
|
||||
title: new Text('One-line'),
|
||||
trailing: new Radio<MaterialListType>(
|
||||
value: _showAvatars ? MaterialListType.oneLineWithAvatar : MaterialListType.oneLine,
|
||||
groupValue: _itemType,
|
||||
onChanged: changeItemType
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
dense: true,
|
||||
title: new Text('Two-line'),
|
||||
trailing: new Radio<MaterialListType>(
|
||||
value: MaterialListType.twoLine,
|
||||
groupValue: _itemType,
|
||||
onChanged: changeItemType
|
||||
)
|
||||
),
|
||||
new ListItem(
|
||||
dense: true,
|
||||
title: new Text('Three-line'),
|
||||
trailing: new Radio<MaterialListType>(
|
||||
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<Widget> 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: <Widget>[
|
||||
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
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
// 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<MenuDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
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<String> _checkedValues;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_simpleValue = _simpleValue2;
|
||||
_checkedValues = <String>[_checkedValue3];
|
||||
}
|
||||
|
||||
void showInSnackBar(String value) {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
content: new Text(value)
|
||||
));
|
||||
}
|
||||
|
||||
void showMenuSelection(String value) {
|
||||
if (<String>[_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: <Widget>[
|
||||
new PopupMenuButton<String>(
|
||||
onSelected: showMenuSelection,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Toolbar menu',
|
||||
child: new Text('Toolbar menu')
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Right here',
|
||||
child: new Text('Right here')
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Hooray!',
|
||||
child: new Text('Hooray!')
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
body: new Block(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
children: <Widget>[
|
||||
// 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<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
onSelected: showMenuSelection,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||
new PopupMenuItem<String>(
|
||||
value: _simpleValue1,
|
||||
child: new Text('Context menu item one')
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
enabled: false,
|
||||
child: new Text('A disabled menu item')
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
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<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
onSelected: showMenuSelection,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Preview',
|
||||
child: new ListItem(
|
||||
leading: new Icon(icon: Icons.visibility),
|
||||
title: new Text('Preview')
|
||||
)
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Share',
|
||||
child: new ListItem(
|
||||
leading: new Icon(icon: Icons.person_add),
|
||||
title: new Text('Share')
|
||||
)
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
value: 'Get Link',
|
||||
child: new ListItem(
|
||||
leading: new Icon(icon: Icons.link),
|
||||
title: new Text('Get link')
|
||||
)
|
||||
),
|
||||
new PopupMenuDivider(),
|
||||
new PopupMenuItem<String>(
|
||||
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<String>(
|
||||
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) => <PopupMenuItem<String>>[
|
||||
new PopupMenuItem<String>(
|
||||
value: _simpleValue1,
|
||||
child: new Text(_simpleValue1)
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
value: _simpleValue2,
|
||||
child: new Text(_simpleValue2)
|
||||
),
|
||||
new PopupMenuItem<String>(
|
||||
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<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
onSelected: showCheckedMenuSelections,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
|
||||
new CheckedPopupMenuItem<String>(
|
||||
value: _checkedValue1,
|
||||
checked: isChecked(_checkedValue1),
|
||||
child: new Text(_checkedValue1)
|
||||
),
|
||||
new CheckedPopupMenuItem<String>(
|
||||
value: _checkedValue2,
|
||||
enabled: false,
|
||||
checked: isChecked(_checkedValue2),
|
||||
child: new Text(_checkedValue2)
|
||||
),
|
||||
new CheckedPopupMenuItem<String>(
|
||||
value: _checkedValue3,
|
||||
checked: isChecked(_checkedValue3),
|
||||
child: new Text(_checkedValue3)
|
||||
),
|
||||
new CheckedPopupMenuItem<String>(
|
||||
value: _checkedValue4,
|
||||
checked: isChecked(_checkedValue4),
|
||||
child: new Text(_checkedValue4)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
// 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/*<Null>*/(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
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
// 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<OverscrollDemo> {
|
||||
static final List<String> _items = <String>[
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'
|
||||
];
|
||||
|
||||
IndicatorType _type = IndicatorType.refresh;
|
||||
|
||||
Future<Null> refresh() {
|
||||
Completer<Null> completer = new Completer<Null>();
|
||||
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: <Widget>[
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
// 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<IconData> selection = TabBarSelection.of/*<IconData>*/(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<IconData> icons = <IconData>[
|
||||
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<IconData>(
|
||||
values: icons,
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
final Color color = Theme.of(context).accentColor;
|
||||
return new Column(
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
margin: const EdgeInsets.only(top: 16.0),
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new IconButton(
|
||||
icon: Icons.arrow_back,
|
||||
color: color,
|
||||
onPressed: () { _handleArrowButtonPress(context, -1); },
|
||||
tooltip: 'Page back'
|
||||
),
|
||||
new TabPageSelector<IconData>(),
|
||||
new IconButton(
|
||||
icon: Icons.arrow_forward,
|
||||
color: color,
|
||||
onPressed: () { _handleArrowButtonPress(context, 1); },
|
||||
tooltip: 'Page forward'
|
||||
)
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween
|
||||
)
|
||||
),
|
||||
new Flexible(
|
||||
child: new TabBarView<IconData>(
|
||||
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()
|
||||
)
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
// 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<PersistentBottomSheetDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
VoidCallback _showBottomSheetCallback;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_showBottomSheetCallback = showBottomSheet;
|
||||
}
|
||||
|
||||
|
||||
void showBottomSheet() {
|
||||
setState(() { // disable the button
|
||||
_showBottomSheetCallback = null;
|
||||
});
|
||||
_scaffoldKey.currentState.showBottomSheet/*<Null>*/((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')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
// 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<ProgressIndicatorDemo> {
|
||||
AnimationController _controller;
|
||||
Animation<double> _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<Widget> indicators = <Widget>[
|
||||
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
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
// 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<ScrollableTabsDemo> {
|
||||
final List<IconData> icons = <IconData>[
|
||||
Icons.event,
|
||||
Icons.home,
|
||||
Icons.android,
|
||||
Icons.alarm,
|
||||
Icons.face,
|
||||
Icons.language,
|
||||
];
|
||||
|
||||
final Map<IconData, String> labels = <IconData, String>{
|
||||
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<IconData>(
|
||||
values: icons,
|
||||
child: new Scaffold(
|
||||
appBar: new AppBar(
|
||||
title: new Text('Scrollable tabs'),
|
||||
actions: <Widget>[
|
||||
new PopupMenuButton<TabsDemoStyle>(
|
||||
onSelected: changeDemoStyle,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<TabsDemoStyle>>[
|
||||
new PopupMenuItem<TabsDemoStyle>(
|
||||
value: TabsDemoStyle.iconsAndText,
|
||||
child: new Text('Icons and text')
|
||||
),
|
||||
new PopupMenuItem<TabsDemoStyle>(
|
||||
value: TabsDemoStyle.iconsOnly,
|
||||
child: new Text('Icons only')
|
||||
),
|
||||
new PopupMenuItem<TabsDemoStyle>(
|
||||
value: TabsDemoStyle.textOnly,
|
||||
child: new Text('Text only')
|
||||
),
|
||||
]
|
||||
)
|
||||
],
|
||||
tabBar: new TabBar<IconData>(
|
||||
isScrollable: true,
|
||||
labels: new Map<IconData, TabLabel>.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<IconData>(
|
||||
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()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
// 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: <Widget>[
|
||||
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<Widget> barGraphics;
|
||||
final WidgetBuilder builder;
|
||||
|
||||
void showDemo(BuildContext context) {
|
||||
Navigator.push(context, new MaterialPageRoute<Null>(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 :<Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
new _StatusBarGraphic(),
|
||||
new _AppBarGraphic()
|
||||
]
|
||||
),
|
||||
new _TechniqueItem(
|
||||
titleText: 'Tabs',
|
||||
builder: (BuildContext context) => new FlexibleSpaceDemo(),
|
||||
barGraphics: <Widget>[
|
||||
new _StatusBarGraphic(),
|
||||
new _AppBarGraphic(),
|
||||
new _TabBarGraphic()
|
||||
]
|
||||
),
|
||||
new _TechniqueItem(
|
||||
titleText: 'Flexible',
|
||||
builder: (BuildContext context) => new FlexibleSpaceDemo(),
|
||||
barGraphics: <Widget>[
|
||||
new _StatusBarGraphic(),
|
||||
new _AppBarGraphic(),
|
||||
new _FlexibleSpaceGraphic()
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
// 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<SelectionControlsDemo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<ComponentDemoTabData> demos = <ComponentDemoTabData>[
|
||||
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: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.collapse,
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
// 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: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.collapse,
|
||||
children: <Widget>[
|
||||
new Radio<int>(
|
||||
value: 0,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 1,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 2,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
)
|
||||
]
|
||||
),
|
||||
// Disabled radio buttons
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.collapse,
|
||||
children: <Widget>[
|
||||
new Radio<int>(
|
||||
value: 0,
|
||||
groupValue: 0
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 1,
|
||||
groupValue: 0
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 2,
|
||||
groupValue: 0
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSwitch() {
|
||||
return new Align(
|
||||
alignment: new FractionalOffset(0.5, 0.4),
|
||||
child: new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.collapse,
|
||||
children: <Widget>[
|
||||
new Switch(value: switchValue, onChanged: (bool value) {
|
||||
setState(() {
|
||||
switchValue = value;
|
||||
});
|
||||
}),
|
||||
// Disabled switches
|
||||
new Switch(value: true),
|
||||
new Switch(value: false)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// 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<SliderDemo> {
|
||||
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: <Widget>[
|
||||
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;
|
||||
});
|
||||
}
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
// 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<SnackBarDemo> {
|
||||
int _snackBarIndex = 1;
|
||||
|
||||
Widget buildBody(BuildContext context) {
|
||||
return new Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: new Block(
|
||||
children: <Widget>[
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
// 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<ScrollableState<Scrollable>> key = new GlobalKey<ScrollableState<Scrollable>>();
|
||||
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<TabsDemo> {
|
||||
_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<Widget>.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()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
// 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<int, Color> 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<Color>(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<TabsFabDemo> {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
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<String>(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())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
// 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<TextFieldDemo> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
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: <Widget>[
|
||||
new Input(
|
||||
hintText: 'What do people call you?',
|
||||
labelText: 'Name',
|
||||
formField: new FormField<String>(
|
||||
// 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<String>(
|
||||
setter: (String val) { person.phoneNumber = val; },
|
||||
validator: _validatePhoneNumber
|
||||
)
|
||||
),
|
||||
new Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new Flexible(
|
||||
child: new Input(
|
||||
hintText: 'How do you log in?',
|
||||
labelText: 'New Password',
|
||||
hideText: true,
|
||||
formField: new FormField<String>(
|
||||
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<String>(
|
||||
validator: _validatePassword
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// 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<TimePickerDemo> {
|
||||
TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 28);
|
||||
|
||||
Future<Null> _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: <Widget>[
|
||||
new Text('$_selectedTime'),
|
||||
new SizedBox(height: 20.0),
|
||||
new RaisedButton(
|
||||
onPressed: _handleSelectTime,
|
||||
child: new Text('SELECT TIME')
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
// 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: <Widget>[
|
||||
new Text(_introText, style: theme.textTheme.subhead),
|
||||
new Row(
|
||||
children: <Widget>[
|
||||
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()
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// 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: <Widget>[
|
||||
new TwoLevelListItem(title: new Text('Top')),
|
||||
new TwoLevelSublist(
|
||||
title: new Text('Sublist'),
|
||||
children: <Widget>[
|
||||
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'))
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
// 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: <Widget>[
|
||||
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<Widget> styleItems = <Widget>[
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,559 +0,0 @@
|
||||
// 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<WeatherDemo> {
|
||||
|
||||
Future<Null> _loadAssets(AssetBundle bundle) async {
|
||||
_images = new ImageMap(bundle);
|
||||
await _images.load(<String>[
|
||||
'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: <Widget>[
|
||||
new SpriteWidget(weatherWorld),
|
||||
new Align(
|
||||
alignment: new FractionalOffset(0.5, 0.8),
|
||||
child: new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
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<Color> _kBackgroundColorsTop = const <Color>[
|
||||
const Color(0xff5ebbd5),
|
||||
const Color(0xff0b2734),
|
||||
const Color(0xffcbced7)
|
||||
];
|
||||
|
||||
const List<Color> _kBackgroundColorsBottom = const <Color>[
|
||||
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: <Color>[colorTop, colorBottom],
|
||||
stops: <double>[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<Sprite> _sprites = <Sprite>[];
|
||||
|
||||
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 = <Ray>[];
|
||||
for (int i = 0; i < _kNumSunRays; i += 1) {
|
||||
Ray ray = new Ray();
|
||||
addChild(ray);
|
||||
_rays.add(ray);
|
||||
}
|
||||
}
|
||||
|
||||
Sprite _sun;
|
||||
List<Ray> _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(<Action>[
|
||||
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(<Action>[
|
||||
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<ParticleSystem> _particles = <ParticleSystem>[];
|
||||
|
||||
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<ParticleSystem> _particles = <ParticleSystem>[];
|
||||
|
||||
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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
// 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<String, WidgetBuilder> kRoutes = <String, WidgetBuilder>{
|
||||
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<GalleryApp> {
|
||||
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; }); }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
// 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<ComponentDemoTabData, TabLabel> buildTabLabels(List<ComponentDemoTabData> demos) {
|
||||
return new Map<ComponentDemoTabData, TabLabel>.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<ComponentDemoTabData> demos;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new TabBarSelection<ComponentDemoTabData>(
|
||||
values: demos,
|
||||
child: new Scaffold(
|
||||
appBar: new AppBar(
|
||||
title: new Text(title),
|
||||
tabBar: new TabBar<ComponentDemoTabData>(
|
||||
isScrollable: true,
|
||||
labels: ComponentDemoTabData.buildTabLabels(demos)
|
||||
)
|
||||
),
|
||||
body: new TabbedComponentDemo(demos)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TabbedComponentDemo extends StatelessWidget {
|
||||
TabbedComponentDemo(this.demos);
|
||||
|
||||
final List<ComponentDemoTabData> demos;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new TabBarView<ComponentDemoTabData>(
|
||||
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: <Widget>[
|
||||
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<FullScreenCodeDialog>(
|
||||
builder: (BuildContext context) => new FullScreenCodeDialog(exampleCodeTag: exampleCodeTag)
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
return new Column(
|
||||
children: <Widget>[
|
||||
new Divider(
|
||||
height: 1.0
|
||||
),
|
||||
new Container(
|
||||
height: 48.0,
|
||||
child: new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new FlatButton(
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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<FormattedCode> {
|
||||
@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: <TextSpan>[new DartSyntaxHighlighter().format(config.exampleCode)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FullScreenCodeDialog extends StatefulWidget {
|
||||
FullScreenCodeDialog({ this.exampleCodeTag });
|
||||
|
||||
final String exampleCodeTag;
|
||||
|
||||
@override
|
||||
FullScreenCodeDialogState createState() => new FullScreenCodeDialogState();
|
||||
}
|
||||
|
||||
class FullScreenCodeDialogState extends State<FullScreenCodeDialog> {
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
// 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<bool> onThemeChanged;
|
||||
|
||||
final double timeDilation;
|
||||
final ValueChanged<double> onTimeDilationChanged;
|
||||
|
||||
final bool showPerformanceOverlay;
|
||||
final ValueChanged<bool> onShowPerformanceOverlayChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Drawer(
|
||||
child: new Block(
|
||||
children: <Widget>[
|
||||
new DrawerHeader(child: new Text('Flutter gallery')),
|
||||
new DrawerItem(
|
||||
icon: Icons.brightness_5,
|
||||
onPressed: () { onThemeChanged(true); },
|
||||
selected: useLightTheme,
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Flexible(child: new Text('Light')),
|
||||
new Radio<bool>(
|
||||
value: true,
|
||||
groupValue: useLightTheme,
|
||||
onChanged: onThemeChanged
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
new DrawerItem(
|
||||
icon: Icons.brightness_7,
|
||||
onPressed: () { onThemeChanged(false); },
|
||||
selected: useLightTheme,
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Flexible(child: new Text('Dark')),
|
||||
new Radio<bool>(
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
new Flexible(child: new Text('Performance Overlay')),
|
||||
new Checkbox(
|
||||
value: showPerformanceOverlay,
|
||||
onChanged: (bool value) { onShowPerformanceOverlayChanged(!showPerformanceOverlay); }
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
// 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<String>(
|
||||
value: dropdownValue,
|
||||
onChanged: (String newValue) {
|
||||
// null indicates the user didn't select a
|
||||
// new value.
|
||||
setState(() {
|
||||
if (newValue != null)
|
||||
dropdownValue = newValue;
|
||||
});
|
||||
},
|
||||
items: <String>['One', 'Two', 'Free', 'Four']
|
||||
.map((String value) {
|
||||
return new DropDownMenuItem<String>(
|
||||
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: <Widget>[
|
||||
new Radio<int>(
|
||||
value: 0,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 1,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
),
|
||||
new Radio<int>(
|
||||
value: 2,
|
||||
groupValue: radioValue,
|
||||
onChanged: handleRadioValueChanged
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
// Creates a disabled radio button.
|
||||
new Radio<int>(
|
||||
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: <String>[
|
||||
'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
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// 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<String, String> _exampleCode;
|
||||
|
||||
Future<String> getExampleCode(String tag, AssetBundle bundle) async {
|
||||
if (_exampleCode == null)
|
||||
await _parseExampleCode(bundle);
|
||||
return _exampleCode[tag];
|
||||
}
|
||||
|
||||
Future<Null> _parseExampleCode(AssetBundle bundle) async {
|
||||
final String code = await bundle.loadString('lib/gallery/example_code.dart');
|
||||
_exampleCode = <String, String>{};
|
||||
|
||||
final List<String> lines = code.split('\n');
|
||||
|
||||
List<String> codeBlock;
|
||||
String codeTag;
|
||||
|
||||
for (String line in lines) {
|
||||
if (codeBlock == null) {
|
||||
// Outside a block.
|
||||
if (line.startsWith(_kStartTag)) {
|
||||
// Starting a new code block.
|
||||
codeBlock = <String>[];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,198 +0,0 @@
|
||||
// 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<GalleryHeader> {
|
||||
_FlutterHeaderNode _headerNode;
|
||||
ImageMap _images;
|
||||
|
||||
Future<Null> _loadAssets() async {
|
||||
final AssetBundle bundle = DefaultAssetBundle.of(context);
|
||||
_images = new ImageMap(bundle);
|
||||
await _images.load(<String>[
|
||||
'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 = <Constraint>[
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
// 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<bool> onThemeChanged;
|
||||
|
||||
final double timeDilation;
|
||||
final ValueChanged<double> onTimeDilationChanged;
|
||||
|
||||
final bool showPerformanceOverlay;
|
||||
final ValueChanged<bool> onShowPerformanceOverlayChanged;
|
||||
|
||||
@override
|
||||
GalleryHomeState createState() => new GalleryHomeState();
|
||||
}
|
||||
|
||||
class GalleryHomeState extends State<GalleryHome> {
|
||||
final Key _homeKey = new ValueKey<String>("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: <Widget>[
|
||||
new TwoLevelSublist(
|
||||
leading: new Icon(icon: Icons.star),
|
||||
title: new Text('Demos'),
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
new GalleryItem(title: 'Colors', routeName: ColorsDemo.routeName),
|
||||
new GalleryItem(title: 'Typography', routeName: TypographyDemo.routeName),
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// 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: <String, String>{
|
||||
'from': '/',
|
||||
'to': routeName
|
||||
});
|
||||
Navigator.pushNamed(context, routeName);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,345 +0,0 @@
|
||||
// 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<String> _kKeywords = const <String>[
|
||||
'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<String> _kBuiltInTypes = const <String>[
|
||||
'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<TextSpan> formattedText = <TextSpan>[];
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// 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());
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
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
|
@ -1,53 +0,0 @@
|
||||
// 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<String> loadString(String key) {
|
||||
if (key == 'lib/gallery/example_code.dart')
|
||||
return new Future<String>.value(testCodeFile);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<core.MojoDataPipeConsumer> load(String key) => null;
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType@$hashCode()';
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
// 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<String> demoCategories = const <String>['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<double> scrollDeltas = new List<double>();
|
||||
double previousY = tester.getTopRight(find.text(demoCategories[0])).y;
|
||||
final List<String> 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);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// 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();
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// 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<Null>.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<Null>.delayed(new Duration(milliseconds: 500));
|
||||
}
|
||||
});
|
||||
|
||||
new TimelineSummary.summarize(timeline)
|
||||
..writeSummaryToFile('home_scroll_perf', pretty: true)
|
||||
..writeTimelineToFile('home_scroll_perf', pretty: true);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// 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();
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
// 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<String> demoCategories = const <String>['Demos', 'Components', 'Style'];
|
||||
|
||||
const List<String> demoNames = const <String>[
|
||||
'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<Null>.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<Null>.delayed(new Duration(milliseconds: 500));
|
||||
|
||||
for(int i = 0; i < 2; i += 1) {
|
||||
await driver.tap(menuItem); // Launch the demo
|
||||
await new Future<Null>.delayed(new Duration(milliseconds: 500));
|
||||
await driver.tap(find.byTooltip('Back'));
|
||||
await new Future<Null>.delayed(new Duration(milliseconds: 1000));
|
||||
}
|
||||
}
|
||||
},
|
||||
categories: const <TracingCategory>[
|
||||
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)));
|
||||
});
|
||||
}
|