Commit 475d5a45 authored by Hans Muller's avatar Hans Muller

remove spurious copy of the material_gallery directory (#3806)

parent cc931708
.DS_Store
.atom/
.idea
.packages
.pub/
build/
ios/.generated/
packages
pubspec.lock
# 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.
<?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>
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
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
{
"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"
}
]
}
\ No newline at end of file
<?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>
<?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>
// 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';
// 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
}
)
);
}
}
// 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()
)
);
}
}
// 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()
)
);
}
}
// 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()
)
)
);
}
}
// 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)
)
]
)
)
)
]
)
);
}
}
// 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
)
);
}
}
// 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()
));
}
)
]
)
);
}
}
// 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;
}
}
// 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;
});
}
)
)
);
}
}
// 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);
}
}
// 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'
]
)
]
)
]
)
)
);
}
}
// 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()
)
);
}
}
// 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
)
]
)
);
}
}
// 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)
),
]
)
)
)
)
]
)
)
)
);
}
}
// 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()
)
);
}
}
// 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
)
)
)
);
}
}
// 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)
)
]
)
)
]
)
);
}
}
// 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
)
)
);
});
}
)
)
);
}
}
// 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
);
}
}
// 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()
)
)
]
);
}
)
)
);
}
}
// 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')
)
)
);
}
}
// 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
)
)
)
)
);
}
}
// 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()
)
)
);
}
}
// 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()
]
)
]
)
)
);
}
}
// 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)
]
)
);
}
}
// 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;
});
}
)
),
]
)
);
}
}
// 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
)
);
}
}
// 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()
)
)
);
}
}
// 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())
)
);
}
}
// 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
)
)
)
]
)
]
)
)
);
}
}
// 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')
),
]
)
);
}
}
// 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()
);
}
)
);
}
}
// 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'))
]
)
);
}
}
// 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)
);
}
}
// 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
));
}
}
}
}
// 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; }); }
)
);
}
}
// 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
);
}
}
// 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); }
)
]
)
),
]
)
);
}
}
// 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
}
}
// 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);
}
}
}
}
// 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);
}
}
// 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),
]
)
]
)
);
}
}
// 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);
}
}
);
}
}
// 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;
}
}
// 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());
}
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
// 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()';
}
// 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);
}
// 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();
}
// 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);
});
});
}
// 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();
}
// 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)));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment