Commit 219e189a authored by Kris Giesing's avatar Kris Giesing

Merge branch 'master' into doubletap

parents 18e154d4 33c7820d
......@@ -34,10 +34,6 @@ class Field extends StatelessComponent {
}
class AddressBookHome extends StatelessComponent {
AddressBookHome({ this.navigator });
final NavigatorState navigator;
Widget buildToolBar(BuildContext context) {
return new ToolBar(
left: new IconButton(icon: "navigation/arrow_back"),
......@@ -60,22 +56,20 @@ class AddressBookHome extends StatelessComponent {
static final GlobalKey noteKey = new GlobalKey(label: 'note field');
Widget buildBody(BuildContext context) {
return new Material(
child: new Block([
new AspectRatio(
aspectRatio: 16.0 / 9.0,
child: new Container(
decoration: new BoxDecoration(backgroundColor: Colors.purple[300])
)
),
new Field(inputKey: nameKey, icon: "social/person", placeholder: "Name"),
new Field(inputKey: phoneKey, icon: "communication/phone", placeholder: "Phone"),
new Field(inputKey: emailKey, icon: "communication/email", placeholder: "Email"),
new Field(inputKey: addressKey, icon: "maps/place", placeholder: "Address"),
new Field(inputKey: ringtoneKey, icon: "av/volume_up", placeholder: "Ringtone"),
new Field(inputKey: noteKey, icon: "content/add", placeholder: "Add note"),
])
);
return new Block([
new AspectRatio(
aspectRatio: 16.0 / 9.0,
child: new Container(
decoration: new BoxDecoration(backgroundColor: Colors.purple[300])
)
),
new Field(inputKey: nameKey, icon: "social/person", placeholder: "Name"),
new Field(inputKey: phoneKey, icon: "communication/phone", placeholder: "Phone"),
new Field(inputKey: emailKey, icon: "communication/email", placeholder: "Email"),
new Field(inputKey: addressKey, icon: "maps/place", placeholder: "Address"),
new Field(inputKey: ringtoneKey, icon: "av/volume_up", placeholder: "Ringtone"),
new Field(inputKey: noteKey, icon: "content/add", placeholder: "Add note"),
]);
}
Widget build(BuildContext context) {
......@@ -98,7 +92,7 @@ void main() {
title: 'Address Book',
theme: theme,
routes: <String, RouteBuilder>{
'/': (RouteArguments args) => new AddressBookHome(navigator: args.navigator)
'/': (RouteArguments args) => new AddressBookHome()
}
));
}
......@@ -14,13 +14,11 @@ class FitnessItemList extends StatelessComponent {
final FitnessItemHandler onDismissed;
Widget build(BuildContext context) {
return new Material(
child: new ScrollableList<FitnessItem>(
padding: const EdgeDims.all(4.0),
items: items,
itemExtent: kFitnessItemHeight,
itemBuilder: (_, item) => item.toRow(onDismissed: onDismissed)
)
return new ScrollableList<FitnessItem>(
padding: const EdgeDims.all(4.0),
items: items,
itemExtent: kFitnessItemHeight,
itemBuilder: (_, item) => item.toRow(onDismissed: onDismissed)
);
}
}
......@@ -69,7 +67,7 @@ class FeedFragmentState extends State<FeedFragment> {
void _showDrawer() {
showDrawer(
navigator: config.navigator,
context: context,
child: new Block([
new DrawerHeader(child: new Text('Fitness')),
new DrawerItem(
......@@ -119,7 +117,7 @@ class FeedFragmentState extends State<FeedFragment> {
void _handleItemDismissed(FitnessItem item) {
config.onItemDeleted(item);
showSnackBar(
navigator: config.navigator,
context: context,
placeholderKey: _snackBarPlaceholderKey,
content: new Text("Item deleted."),
actions: [new SnackBarAction(label: "UNDO", onPressed: () {
......@@ -171,14 +169,13 @@ class FeedFragmentState extends State<FeedFragment> {
Widget buildBody() {
TextStyle style = Theme.of(context).text.title;
if (config.userData == null)
return new Material();
if (config.userData.items.length == 0)
return new Material(
child: new Row(
[new Text("No data yet.\nAdd some!", style: style)],
justifyContent: FlexJustifyContent.center
)
return new Container();
if (config.userData.items.length == 0) {
return new Row(
[new Text("No data yet.\nAdd some!", style: style)],
justifyContent: FlexJustifyContent.center
);
}
switch (_fitnessMode) {
case FitnessMode.feed:
return new FitnessItemList(
......@@ -186,17 +183,15 @@ class FeedFragmentState extends State<FeedFragment> {
onDismissed: _handleItemDismissed
);
case FitnessMode.chart:
return new Material(
child: new Container(
padding: const EdgeDims.all(20.0),
child: buildChart()
)
return new Container(
padding: const EdgeDims.all(20.0),
child: buildChart()
);
}
}
void _handleActionButtonPressed() {
showDialog(config.navigator, (NavigatorState navigator) => new AddItemDialog(navigator)).then((routeName) {
showDialog(context: context, child: new AddItemDialog()).then((routeName) {
if (routeName != null)
config.navigator.pushNamed(routeName);
});
......@@ -225,10 +220,6 @@ class FeedFragmentState extends State<FeedFragment> {
}
class AddItemDialog extends StatefulComponent {
AddItemDialog(this.navigator);
final NavigatorState navigator;
AddItemDialogState createState() => new AddItemDialogState();
}
......@@ -258,16 +249,20 @@ class AddItemDialogState extends State<AddItemDialog> {
return new Dialog(
title: new Text("What are you doing?"),
content: new Block(menuItems),
onDismiss: config.navigator.pop,
onDismiss: () {
Navigator.of(context).pop();
},
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: config.navigator.pop
onPressed: () {
Navigator.of(context).pop();
}
),
new FlatButton(
child: new Text('ADD'),
onPressed: () {
config.navigator.pop(_addItemRoute);
Navigator.of(context).pop(_addItemRoute);
}
),
]
......
......@@ -85,19 +85,17 @@ class MealFragmentState extends State<MealFragment> {
Widget buildBody() {
Meal meal = new Meal(when: new DateTime.now());
return new Material(
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.all(20.0),
child: new BlockBody([
new Text(meal.displayDate),
new Input(
key: descriptionKey,
placeholder: 'Describe meal',
onChanged: _handleDescriptionChanged
),
])
)
return new ScrollableViewport(
child: new Container(
padding: const EdgeDims.all(20.0),
child: new BlockBody([
new Text(meal.displayDate),
new Input(
key: descriptionKey,
placeholder: 'Describe meal',
onChanged: _handleDescriptionChanged
),
])
)
);
}
......
......@@ -55,9 +55,8 @@ class MeasurementRow extends FitnessItemRow {
}
class MeasurementDateDialog extends StatefulComponent {
MeasurementDateDialog({ this.navigator, this.previousDate });
MeasurementDateDialog({ this.previousDate });
final NavigatorState navigator;
final DateTime previousDate;
MeasurementDateDialogState createState() => new MeasurementDateDialogState();
......@@ -89,12 +88,14 @@ class MeasurementDateDialogState extends State<MeasurementDateDialog> {
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: config.navigator.pop
onPressed: () {
Navigator.of(context).pop();
}
),
new FlatButton(
child: new Text('OK'),
onPressed: () {
config.navigator.pop(_selectedDate);
Navigator.of(context).pop(_selectedDate);
}
),
]
......@@ -124,7 +125,7 @@ class MeasurementFragmentState extends State<MeasurementFragment> {
} on FormatException catch(e) {
print("Exception $e");
showSnackBar(
navigator: config.navigator,
context: context,
placeholderKey: _snackBarPlaceholderKey,
content: new Text('Save failed')
);
......@@ -157,43 +158,41 @@ class MeasurementFragmentState extends State<MeasurementFragment> {
static final GlobalKey weightKey = new GlobalKey();
void _handleDatePressed() {
showDialog(config.navigator, (NavigatorState navigator) {
return new MeasurementDateDialog(navigator: navigator, previousDate: _when);
}).then((DateTime value) {
if (value == null)
return;
Future _handleDatePressed() async {
DateTime value = await showDialog(
context: context,
child: new MeasurementDateDialog(previousDate: _when)
);
if (value != null) {
setState(() {
_when = value;
});
});
}
}
Widget buildBody(BuildContext context) {
Measurement measurement = new Measurement(when: _when);
// TODO(jackson): Revisit the layout of this pane to be more maintainable
return new Material(
child: new Container(
padding: const EdgeDims.all(20.0),
child: new Column([
new GestureDetector(
onTap: _handleDatePressed,
child: new Container(
height: 50.0,
child: new Column([
new Text('Measurement Date'),
new Text(measurement.displayDate, style: Theme.of(context).text.caption),
], alignItems: FlexAlignItems.start)
)
),
new Input(
key: weightKey,
placeholder: 'Enter weight',
keyboardType: KeyboardType.NUMBER,
onChanged: _handleWeightChanged
),
], alignItems: FlexAlignItems.stretch)
)
return new Container(
padding: const EdgeDims.all(20.0),
child: new Column([
new GestureDetector(
onTap: _handleDatePressed,
child: new Container(
height: 50.0,
child: new Column([
new Text('Measurement Date'),
new Text(measurement.displayDate, style: Theme.of(context).text.caption),
], alignItems: FlexAlignItems.start)
)
),
new Input(
key: weightKey,
placeholder: 'Enter weight',
keyboardType: KeyboardType.NUMBER,
onChanged: _handleWeightChanged
),
], alignItems: FlexAlignItems.stretch)
);
}
......
......@@ -60,9 +60,10 @@ class SettingsFragmentState extends State<SettingsFragment> {
}
}
void _handleGoalWeightPressed() {
showDialog(config.navigator, (NavigatorState navigator) {
return new Dialog(
Future _handleGoalWeightPressed() async {
double goalWeight = await showDialog(
context: context,
child: new Dialog(
title: new Text("Goal Weight"),
content: new Input(
key: weightGoalKey,
......@@ -71,50 +72,49 @@ class SettingsFragmentState extends State<SettingsFragment> {
onChanged: _handleGoalWeightChanged
),
onDismiss: () {
navigator.pop();
Navigator.of(context).pop();
},
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: () {
navigator.pop();
Navigator.of(context).pop();
}
),
new FlatButton(
child: new Text('SAVE'),
onPressed: () {
navigator.pop(_goalWeight);
Navigator.of(context).pop(_goalWeight);
}
),
]
);
}).then((double goalWeight) => config.updater(goalWeight: goalWeight));
)
);
config.updater(goalWeight: goalWeight);
}
Widget buildSettingsPane(BuildContext context) {
return new Material(
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.symmetric(vertical: 20.0),
child: new BlockBody([
new DrawerItem(
onPressed: () { _handleBackupChanged(!(config.userData.backupMode == BackupMode.enabled)); },
child: new Row([
new Flexible(child: new Text('Back up data to the cloud')),
new Switch(value: config.userData.backupMode == BackupMode.enabled, onChanged: _handleBackupChanged),
])
),
new DrawerItem(
onPressed: () => _handleGoalWeightPressed(),
child: new Column([
new Text('Goal Weight'),
new Text(goalWeightText, style: Theme.of(context).text.caption),
],
alignItems: FlexAlignItems.start
)
),
])
)
return new ScrollableViewport(
child: new Container(
padding: const EdgeDims.symmetric(vertical: 20.0),
child: new BlockBody([
new DrawerItem(
onPressed: () { _handleBackupChanged(!(config.userData.backupMode == BackupMode.enabled)); },
child: new Row([
new Flexible(child: new Text('Back up data to the cloud')),
new Switch(value: config.userData.backupMode == BackupMode.enabled, onChanged: _handleBackupChanged),
])
),
new DrawerItem(
onPressed: () => _handleGoalWeightPressed(),
child: new Column([
new Text('Goal Weight'),
new Text(goalWeightText, style: Theme.of(context).text.caption),
],
alignItems: FlexAlignItems.start
)
),
])
)
);
}
......
name: fitness
version: 0.0.1
update_url: http://localhost:9888/examples/fitness/
update-url: http://localhost:9888/examples/fitness/
material-design-icons:
- name: action/assessment
- name: action/help
......
......@@ -16,7 +16,7 @@ abstract class GameObject extends Node {
Paint _paintDebug = new Paint()
..color=new Color(0xffff0000)
..strokeWidth = 1.0
..setStyle(ui.PaintingStyle.stroke);
..style = ui.PaintingStyle.stroke;
bool collidingWith(GameObject obj) {
return (GameMath.distanceBetweenPoints(position, obj.position)
......
......@@ -159,7 +159,7 @@ class TextureButtonState extends State<TextureButton> {
width: config.width,
height: config.height,
child: new CustomPaint(
callback: paintCallback,
onPaint: paintCallback,
token: new _TextureButtonToken(
_highlight,
config.texture,
......
......@@ -10,7 +10,7 @@ class PowerBar extends NodeWithSize {
Paint _paintOutline = new Paint()
..color = new Color(0xffffffff)
..strokeWidth = 1.0
..setStyle(ui.PaintingStyle.stroke);
..style = ui.PaintingStyle.stroke;
void paint(PaintingCanvas canvas) {
applyTransformForPivot(canvas);
......
import 'dart:ui';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
......@@ -46,23 +47,39 @@ main() async {
class TestBed extends NodeWithSize {
Sprite _obstacle;
PhysicsNode _physicsNode;
PhysicsWorld _physicsNode;
TestBed() : super(new Size(1024.0, 1024.0)) {
_physicsNode = new PhysicsNode(new Offset(0.0, 100.0));
_physicsNode = new PhysicsWorld(new Offset(0.0, 100.0));
PhysicsGroup group = new PhysicsGroup();
_physicsNode.addChild(group);
_obstacle = new Sprite(_spriteSheet["ship.png"]);
_obstacle.position = new Point(532.0, 800.0);
_obstacle.position = new Point(512.0, 800.0);
_obstacle.size = new Size(64.0, 64.0);
_obstacle.scale = 2.0;
_obstacle.physicsBody = new PhysicsBody(
new PhysicsShapeCircle(Point.origin, 32.0),
type: PhysicsBodyType.static,
friction: 0.5,
tag: "obstacle"
);
_physicsNode.addChild(_obstacle);
group.addChild(_obstacle);
_physicsNode.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin);
// Animate obstacle
ActionSequence seq = new ActionSequence([
new ActionTween((a) => _obstacle.position = a, new Point(256.0, 800.0), new Point(768.0, 800.0), 1.0, Curves.easeInOut),
new ActionTween((a) => _obstacle.position = a, new Point(768.0, 800.0), new Point(256.0, 800.0), 1.0, Curves.easeInOut)
]);
_obstacle.actions.run(new ActionRepeatForever(seq));
seq = new ActionSequence([
new ActionTween((a) => _obstacle.scale = a, 1.0, 2.0, 2.0, Curves.easeInOut),
new ActionTween((a) => _obstacle.scale = a, 2.0, 1.0, 2.0, Curves.easeInOut)
]);
_obstacle.actions.run(new ActionRepeatForever(seq));
addChild(_physicsNode);
userInteractionEnabled = true;
......
......@@ -36,9 +36,10 @@ void drawText(ui.Canvas canvas, String lh) {
path.lineTo(block.maxContentWidth, block.alphabeticBaseline);
path.moveTo(0.0, block.height);
path.lineTo(block.maxContentWidth, block.height);
paint.color = const ui.Color(0xFFFF9000);
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
paint
..color = const ui.Color(0xFFFF9000)
..style = ui.PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawPath(path, paint);
// paint the text
......@@ -49,9 +50,9 @@ ui.Picture paint(ui.Rect paintBounds) {
ui.PictureRecorder recorder = new ui.PictureRecorder();
ui.Canvas canvas = new ui.Canvas(recorder, paintBounds);
ui.Paint paint = new ui.Paint();
paint.color = const ui.Color(0xFFFFFFFF);
paint.setStyle(ui.PaintingStyle.fill);
ui.Paint paint = new ui.Paint()
..color = const ui.Color(0xFFFFFFFF)
..style = ui.PaintingStyle.fill;
canvas.drawRect(new ui.Rect.fromLTRB(0.0, 0.0, ui.view.width, ui.view.height), paint);
canvas.translate(10.0, 0.0);
......
......@@ -29,7 +29,7 @@ ui.Picture paint(ui.Rect paintBounds) {
[new ui.Point(-radius, -radius), new ui.Point(0.0, 0.0)],
[const ui.Color(0xFFFFFF00), const ui.Color(0xFF0000FF)]);
canvas.drawRect(new ui.Rect.fromLTRB(-radius, -radius, radius, radius),
new ui.Paint()..setShader(yellowBlue));
new ui.Paint()..shader = yellowBlue);
// Scale x and y by 0.5.
var scaleMatrix = new Float64List.fromList([
......
......@@ -37,7 +37,7 @@ RenderBox getBox(double lh) {
padding: new EdgeDims.all(10.0),
child: new RenderCustomPaint(
child: paragraph,
callback: (canvas, size) {
onPaint: (PaintingCanvas canvas, Size size) {
double baseline = paragraph.getDistanceToBaseline(TextBaseline.alphabetic);
double w = paragraph.getMaxIntrinsicWidth(new BoxConstraints.loose(size));
double h = paragraph.getMaxIntrinsicHeight(new BoxConstraints.loose(size));
......@@ -48,10 +48,10 @@ RenderBox getBox(double lh) {
path.lineTo(w, baseline);
path.moveTo(0.0, h);
path.lineTo(w, h);
Paint paint = new Paint();
paint.color = const Color(0xFFFF9000);
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
Paint paint = new Paint()
..color = const Color(0xFFFF9000)
..style = ui.PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawPath(path, paint);
}
)
......
......@@ -18,7 +18,8 @@ RenderBox buildFlexExample() {
void addFlexChildSolidColor(RenderFlex parent, ui.Color backgroundColor, { int flex: 0 }) {
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
final FlexParentData childParentData = child.parentData;
childParentData.flex = flex;
}
// Yellow bar at top
......
......@@ -49,7 +49,8 @@ void main() {
void addFlexChildSolidColor(RenderFlex parent, Color backgroundColor, { int flex: 0 }) {
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
final FlexParentData childParentData = child.parentData;
childParentData.flex = flex;
}
var row = new RenderFlex(direction: FlexDirection.horizontal);
......@@ -90,7 +91,8 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
addFlexChildSolidColor(column, const Color(0xFF0081C6), flex: 2);
row.add(column);
column.parentData.flex = 8;
final FlexParentData childParentData = column.parentData;
childParentData.flex = 8;
RenderDecoratedBox root = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF)),
......
......@@ -16,7 +16,8 @@ void main() {
RenderObject child = new RenderSolidColorBox(const Color(0xFFFFFF00));
flexRoot.add(child);
child.parentData.flex = 2;
FlexParentData childParentData = child.parentData;
childParentData.flex = 2;
// The internet is a beautiful place. https://baconipsum.com/
String meatyString = """Bacon ipsum dolor amet ham fatback tri-tip, prosciutto
......@@ -33,7 +34,8 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
child: new RenderParagraph(text)
);
flexRoot.add(child);
child.parentData.flex = 1;
childParentData = child.parentData;
childParentData.flex = 1;
new FlutterBinding(root: root);
}
......@@ -18,7 +18,8 @@ void main() {
void addFlexChildSolidColor(RenderFlex parent, ui.Color backgroundColor, { int flex: 0 }) {
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
final FlexParentData childParentData = child.parentData;
childParentData.flex = flex;
}
addFlexChildSolidColor(flexRoot, const ui.Color(0xFFFF00FF), flex: 1);
......
......@@ -10,5 +10,10 @@ sky_app("stocks") {
if (is_android) {
apk_name = "Stocks"
} else if (is_ios) {
info_plist = "ios/Info.plist"
launcher_resources = [
"ios/LaunchScreen.storyboardc",
]
}
}
<?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>
<!--
This executable name must match the name of the app provided to the
ios_app GN template
-->
<key>CFBundleExecutable</key>
<string>stocks_app</string>
<key>CFBundleDisplayName</key>
<string>Stocks</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>CFBundleIdentifier</key>
<string>com.google.stocks</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>game_app</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>DTPlatformName</key>
<string>iphonesimulator</string>
<key>DTSDKName</key>
<string>iphonesimulator8.3</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>7.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneSimulator</string>
</array>
</dict>
</plist>
......@@ -81,7 +81,7 @@ class StocksAppState extends State<StocksApp> {
if (path.length != 3)
return null;
if (_stocks.containsKey(path[2]))
return (RouteArguments args) => new StockSymbolViewer(args.navigator, _stocks[path[2]]);
return (RouteArguments args) => new StockSymbolViewer(_stocks[path[2]]);
return null;
}
return null;
......
......@@ -25,7 +25,7 @@ class StockArrow extends StatelessComponent {
// TODO(jackson): This should change colors with the theme
Color color = _colorForPercentChange(percentChange);
const double kSize = 40.0;
var arrow = new CustomPaint(callback: (ui.Canvas canvas, Size size) {
var arrow = new CustomPaint(onPaint: (ui.Canvas canvas, Size size) {
Paint paint = new Paint()..color = color;
paint.strokeWidth = 1.0;
const double padding = 2.0;
......@@ -49,11 +49,11 @@ class StockArrow extends StatelessComponent {
path.lineTo(centerX + w, arrowY + h);
path.lineTo(centerX - w, arrowY + h);
path.close();
paint.setStyle(ui.PaintingStyle.fill);
paint.style = ui.PaintingStyle.fill;
canvas.drawPath(path, paint);
// Draw a circle that circumscribes the arrow.
paint.setStyle(ui.PaintingStyle.stroke);
paint.style = ui.PaintingStyle.stroke;
canvas.drawCircle(new Point(centerX, centerY), r, paint);
});
......
......@@ -67,7 +67,8 @@ class StockHomeState extends State<StockHome> {
}
void _handleMenuShow() {
showStockMenu(config.navigator,
showStockMenu(
context: context,
autorefresh: _autorefresh,
onAutorefreshChanged: _handleAutorefreshChanged
);
......@@ -75,7 +76,7 @@ class StockHomeState extends State<StockHome> {
void _showDrawer() {
showDrawer(
navigator: config.navigator,
context: context,
child: new Block(<Widget>[
new DrawerHeader(child: new Text('Stocks')),
new DrawerItem(
......@@ -86,8 +87,9 @@ class StockHomeState extends State<StockHome> {
new DrawerItem(
icon: 'action/account_balance',
onPressed: () {
showDialog(config.navigator, (NavigatorState navigator) {
return new Dialog(
showDialog(
context: context,
child: new Dialog(
title: new Text('Not Implemented'),
content: new Text('This feature has not yet been implemented.'),
actions: <Widget>[
......@@ -95,18 +97,18 @@ class StockHomeState extends State<StockHome> {
child: new Text('USE IT'),
enabled: false,
onPressed: () {
navigator.pop(false);
config.navigator.pop(false);
}
),
new FlatButton(
child: new Text('OH WELL'),
onPressed: () {
navigator.pop(false);
config.navigator.pop(false);
}
),
]
);
});
)
);
},
child: new Text('Account Balance')
),
......@@ -186,14 +188,16 @@ class StockHomeState extends State<StockHome> {
Widget buildStockList(BuildContext context, Iterable<Stock> stocks) {
return new StockList(
stocks: stocks.toList(),
onAction: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) {
onAction: (Stock stock, Key arrowKey) {
setState(() {
stock.percentChange = 100.0 * (1.0 / stock.lastSale);
stock.lastSale += 1.0;
});
},
onOpen: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) {
config.navigator.pushNamed('/stock/${stock.symbol}');
onOpen: (Stock stock, Key arrowKey) {
Set<Key> mostValuableKeys = new Set<Key>();
mostValuableKeys.add(arrowKey);
config.navigator.pushNamed('/stock/${stock.symbol}', mostValuableKeys: mostValuableKeys);
}
);
}
......@@ -226,7 +230,7 @@ class StockHomeState extends State<StockHome> {
return new ToolBar(
left: new IconButton(
icon: "navigation/arrow_back",
colorFilter: new ui.ColorFilter.mode(Theme.of(context).accentColor, ui.TransferMode.srcATop),
colorFilter: new ColorFilter.mode(Theme.of(context).accentColor, ui.TransferMode.srcATop),
onPressed: _handleSearchEnd
),
center: new Input(
......@@ -244,7 +248,7 @@ class StockHomeState extends State<StockHome> {
void _handleStockPurchased() {
showSnackBar(
navigator: config.navigator,
context: context,
placeholderKey: _snackBarPlaceholderKey,
content: new Text("Stock purchased!"),
actions: <SnackBarAction>[
......
......@@ -12,18 +12,16 @@ class StockList extends StatelessComponent {
final StockRowActionCallback onAction;
Widget build(BuildContext context) {
return new Material(
child: new ScrollableList<Stock>(
items: stocks,
itemExtent: StockRow.kHeight,
itemBuilder: (BuildContext context, Stock stock) {
return new StockRow(
stock: stock,
onPressed: onOpen,
onLongPressed: onAction
);
}
)
return new ScrollableList<Stock>(
items: stocks,
itemExtent: StockRow.kHeight,
itemBuilder: (BuildContext context, Stock stock) {
return new StockRow(
stock: stock,
onPressed: onOpen,
onLongPressed: onAction
);
}
);
}
}
......@@ -8,44 +8,42 @@ enum _MenuItems { autorefresh, autorefreshCheckbox, add, remove }
const double _kMenuMargin = 16.0; // 24.0 on tablet
Future showStockMenu(NavigatorState navigator, { bool autorefresh, ValueChanged onAutorefreshChanged }) async {
Future showStockMenu({BuildContext context, bool autorefresh, ValueChanged onAutorefreshChanged }) async {
switch (await showMenu(
navigator: navigator,
context: context,
position: new MenuPosition(
right: ui.view.paddingRight + _kMenuMargin,
top: ui.view.paddingTop + _kMenuMargin
),
builder: (NavigatorState navigator) {
return <PopupMenuItem>[
new PopupMenuItem(
value: _MenuItems.autorefresh,
child: new Row(<Widget>[
new Flexible(child: new Text('Autorefresh')),
new Checkbox(
value: autorefresh,
onChanged: (bool value) {
navigator.setState(() {
autorefresh = value;
});
navigator.pop(_MenuItems.autorefreshCheckbox);
}
)
]
)
),
new PopupMenuItem(
value: _MenuItems.add,
child: new Text('Add stock')
),
new PopupMenuItem(
value: _MenuItems.remove,
child: new Text('Remove stock')
),
];
}
items: <PopupMenuItem>[
new PopupMenuItem(
value: _MenuItems.autorefresh,
child: new Row(<Widget>[
new Flexible(child: new Text('Autorefresh')),
new Checkbox(
value: autorefresh,
onChanged: (bool value) {
Navigator.of(context).setState(() {
autorefresh = value;
});
Navigator.of(context).pop(_MenuItems.autorefreshCheckbox);
}
)
]
)
),
new PopupMenuItem(
value: _MenuItems.add,
child: new Text('Add stock')
),
new PopupMenuItem(
value: _MenuItems.remove,
child: new Text('Remove stock')
),
]
)) {
case _MenuItems.autorefresh:
navigator.setState(() {
Navigator.of(context).setState(() {
autorefresh = !autorefresh;
});
continue autorefreshNotify;
......@@ -55,8 +53,9 @@ Future showStockMenu(NavigatorState navigator, { bool autorefresh, ValueChanged
break;
case _MenuItems.add:
case _MenuItems.remove:
await showDialog(navigator, (NavigatorState navigator) {
return new Dialog(
await showDialog(
context: context,
child: new Dialog(
title: new Text('Not Implemented'),
content: new Text('This feature has not yet been implemented.'),
actions: <Widget>[
......@@ -76,14 +75,14 @@ Future showStockMenu(NavigatorState navigator, { bool autorefresh, ValueChanged
new FlatButton(
child: new Text('OH WELL'),
onPressed: () {
navigator.pop(false);
Navigator.of(context).pop(false);
}
),
]
);
});
)
);
break;
default:
// menu was canceled.
}
}
\ No newline at end of file
}
......@@ -4,24 +4,24 @@
part of stocks;
enum StockRowPartKind { arrow, symbol, price }
enum StockRowPartKind { arrow }
class StockRowPartGlobalKey extends GlobalKey {
const StockRowPartGlobalKey(this.stock, this.part) : super.constructor();
class StockRowPartKey extends Key {
const StockRowPartKey(this.stock, this.part) : super.constructor();
final Stock stock;
final StockRowPartKind part;
bool operator ==(dynamic other) {
if (other is! StockRowPartGlobalKey)
if (other is! StockRowPartKey)
return false;
final StockRowPartGlobalKey typedOther = other;
final StockRowPartKey typedOther = other;
return stock == typedOther.stock &&
part == typedOther.part;
}
int get hashCode => 37 * (37 * (373) + identityHashCode(stock)) + identityHashCode(part);
String toString() => '[StockRowPartGlobalKey ${stock.symbol}:${part.toString().split(".")[1]})]';
String toString() => '[StockRowPartKey ${stock.symbol}:${part.toString().split(".")[1]})]';
}
typedef void StockRowActionCallback(Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey);
typedef void StockRowActionCallback(Stock stock, Key arrowKey);
class StockRow extends StatelessComponent {
StockRow({
......@@ -29,38 +29,34 @@ class StockRow extends StatelessComponent {
this.onPressed,
this.onLongPressed
}) : this.stock = stock,
arrowKey = new StockRowPartGlobalKey(stock, StockRowPartKind.arrow),
symbolKey = new StockRowPartGlobalKey(stock, StockRowPartKind.symbol),
priceKey = new StockRowPartGlobalKey(stock, StockRowPartKind.price),
super(key: new GlobalObjectKey(stock));
_arrowKey = new StockRowPartKey(stock, StockRowPartKind.arrow),
super(key: new ObjectKey(stock));
final Stock stock;
final StockRowActionCallback onPressed;
final StockRowActionCallback onLongPressed;
final GlobalKey arrowKey;
final GlobalKey symbolKey;
final GlobalKey priceKey;
final Key _arrowKey;
static const double kHeight = 79.0;
GestureTapCallback _getTapHandler(StockRowActionCallback callback) {
if (callback == null)
return null;
return () => callback(stock, key, arrowKey, symbolKey, priceKey);
return () => callback(stock, _arrowKey);
}
GestureLongPressCallback _getLongPressHandler(StockRowActionCallback callback) {
if (callback == null)
return null;
return () => callback(stock, key, arrowKey, symbolKey, priceKey);
return () => callback(stock, _arrowKey);
}
Widget build(BuildContext context) {
String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
final String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
String changeInPrice = "${stock.percentChange.toStringAsFixed(2)}%";
if (stock.percentChange > 0) changeInPrice = "+" + changeInPrice;
if (stock.percentChange > 0)
changeInPrice = "+" + changeInPrice;
return new InkWell(
onTap: _getTapHandler(onPressed),
onLongPress: _getLongPressHandler(onLongPressed),
......@@ -72,39 +68,41 @@ class StockRow extends StatelessComponent {
)
),
child: new Row(<Widget>[
new Container(
key: arrowKey,
child: new StockArrow(percentChange: stock.percentChange),
margin: const EdgeDims.only(right: 5.0)
),
new Flexible(
child: new Row(<Widget>[
new Flexible(
flex: 2,
child: new Text(
stock.symbol,
key: symbolKey
)
),
new Flexible(
child: new Text(
lastSale,
style: const TextStyle(textAlign: TextAlign.right),
key: priceKey
)
),
new Flexible(
child: new Text(
changeInPrice,
style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right)
)
),
],
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(context).textBaseline
)
)
])
new Container(
margin: const EdgeDims.only(right: 5.0),
child: new Hero(
tag: StockRowPartKind.arrow,
key: _arrowKey,
child: new StockArrow(percentChange: stock.percentChange)
)
),
new Flexible(
child: new Row(<Widget>[
new Flexible(
flex: 2,
child: new Text(
stock.symbol
)
),
new Flexible(
child: new Text(
lastSale,
style: const TextStyle(textAlign: TextAlign.right)
)
),
new Flexible(
child: new Text(
changeInPrice,
style: const TextStyle(textAlign: TextAlign.right)
)
),
],
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(context).textBaseline
)
),
]
)
)
);
}
......
......@@ -35,29 +35,30 @@ class StockSettingsState extends State<StockSettings> {
_handleOptimismChanged(false);
break;
case StockMode.pessimistic:
showDialog(config.navigator, (NavigatorState navigator) {
return new Dialog(
showDialog(
context: context,
child: new Dialog(
title: new Text("Change mode?"),
content: new Text("Optimistic mode means everything is awesome. Are you sure you can handle that?"),
onDismiss: () {
navigator.pop(false);
config.navigator.pop(false);
},
actions: <Widget>[
new FlatButton(
child: new Text('NO THANKS'),
onPressed: () {
navigator.pop(false);
config.navigator.pop(false);
}
),
new FlatButton(
child: new Text('AGREE'),
onPressed: () {
navigator.pop(true);
config.navigator.pop(true);
}
),
]
);
}).then(_handleOptimismChanged);
)
).then(_handleOptimismChanged);
break;
}
}
......@@ -83,35 +84,33 @@ class StockSettingsState extends State<StockSettings> {
Widget buildSettingsPane(BuildContext context) {
// TODO(ianh): Once we have the gesture API hooked up, fix https://github.com/domokit/mojo/issues/281
// (whereby tapping the widgets below causes both the widget and the menu item to fire their callbacks)
return new Material(
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.symmetric(vertical: 20.0),
child: new BlockBody(<Widget>[
new DrawerItem(
icon: 'action/thumb_up',
onPressed: () => _confirmOptimismChange(),
child: new Row(<Widget>[
new Flexible(child: new Text('Everything is awesome')),
new Checkbox(
value: config.optimism == StockMode.optimistic,
onChanged: (bool value) => _confirmOptimismChange()
),
])
),
new DrawerItem(
icon: 'action/backup',
onPressed: () { _handleBackupChanged(!(config.backup == BackupMode.enabled)); },
child: new Row(<Widget>[
new Flexible(child: new Text('Back up stock list to the cloud')),
new Switch(
value: config.backup == BackupMode.enabled,
onChanged: _handleBackupChanged
),
])
),
])
)
return new ScrollableViewport(
child: new Container(
padding: const EdgeDims.symmetric(vertical: 20.0),
child: new BlockBody(<Widget>[
new DrawerItem(
icon: 'action/thumb_up',
onPressed: () => _confirmOptimismChange(),
child: new Row(<Widget>[
new Flexible(child: new Text('Everything is awesome')),
new Checkbox(
value: config.optimism == StockMode.optimistic,
onChanged: (bool value) => _confirmOptimismChange()
),
])
),
new DrawerItem(
icon: 'action/backup',
onPressed: () { _handleBackupChanged(!(config.backup == BackupMode.enabled)); },
child: new Row(<Widget>[
new Flexible(child: new Text('Back up stock list to the cloud')),
new Switch(
value: config.backup == BackupMode.enabled,
onChanged: _handleBackupChanged
),
])
),
])
)
);
}
......
......@@ -4,51 +4,59 @@
part of stocks;
class StockSymbolViewer extends StatefulComponent {
StockSymbolViewer(this.navigator, this.stock);
class StockSymbolViewer extends StatelessComponent {
StockSymbolViewer(this.stock);
final NavigatorState navigator;
final Stock stock;
StockSymbolViewerState createState() => new StockSymbolViewerState();
}
class StockSymbolViewerState extends State<StockSymbolViewer> {
Widget build(BuildContext context) {
String lastSale = "\$${config.stock.lastSale.toStringAsFixed(2)}";
String changeInPrice = "${config.stock.percentChange.toStringAsFixed(2)}%";
if (config.stock.percentChange > 0) changeInPrice = "+" + changeInPrice;
String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
String changeInPrice = "${stock.percentChange.toStringAsFixed(2)}%";
if (stock.percentChange > 0)
changeInPrice = "+" + changeInPrice;
TextStyle headings = Theme.of(context).text.body2;
return new Scaffold(
toolBar: new ToolBar(
left: new IconButton(
icon: 'navigation/arrow_back',
onPressed: config.navigator.pop
onPressed: () {
Navigator.of(context).pop();
}
),
center: new Text('${config.stock.name} (${config.stock.symbol})')
center: new Text(stock.name)
),
body: new Material(
child: new Block(<Widget>[
body: new Block(<Widget>[
new Container(
padding: new EdgeDims.all(20.0),
child: new Column(<Widget>[
new Text('Last Sale', style: headings),
new Text('$lastSale ($changeInPrice)'),
new Container(
height: 8.0
),
new Text('Market Cap', style: headings),
new Text('${config.stock.marketCap}'),
],
alignItems: FlexAlignItems.stretch
margin: new EdgeDims.all(20.0),
child: new Card(
child: new Container(
padding: new EdgeDims.all(20.0),
child: new Column(<Widget>[
new Row(<Widget>[
new Text(
'${stock.symbol}',
style: Theme.of(context).text.display2
),
new Hero(
tag: StockRowPartKind.arrow,
turns: 2,
child: new StockArrow(percentChange: stock.percentChange)
),
],
justifyContent: FlexJustifyContent.spaceBetween
),
new Text('Last Sale', style: headings),
new Text('$lastSale ($changeInPrice)'),
new Container(
height: 8.0
),
new Text('Market Cap', style: headings),
new Text('${stock.marketCap}'),
])
)
)
)
])
]
)
);
}
......
name: stocks
version: 0.0.2
update-url: http://localhost:9888/examples/stocks/
material-design-icons:
- name: action/account_balance
- name: action/assessment
......
......@@ -19,10 +19,6 @@ class CardModel {
}
class CardCollection extends StatefulComponent {
CardCollection({ this.navigator });
final NavigatorState navigator;
CardCollectionState createState() => new CardCollectionState();
}
......@@ -113,7 +109,7 @@ class CardCollectionState extends State<CardCollection> {
void _showDrawer() {
showDrawer(
navigator: config.navigator,
context: context,
child: new IconTheme(
data: const IconThemeData(color: IconThemeColor.black),
child: new Block([
......@@ -169,7 +165,7 @@ class CardCollectionState extends State<CardCollection> {
setState(() {
_dismissDirection = newDismissDirection;
});
config.navigator.pop();
Navigator.of(context).pop();
}
Widget buildDrawerCheckbox(String label, bool value, Function callback) {
......@@ -337,7 +333,7 @@ class CardCollectionState extends State<CardCollection> {
]);
Widget body = new SizeObserver(
callback: _updateCardCollectionSize,
onSizeChanged: _updateCardCollectionSize,
child: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
......@@ -348,8 +344,7 @@ class CardCollectionState extends State<CardCollection> {
if (_snapToCenter) {
Widget indicator = new IgnorePointer(
child: new Align(
horizontal: 0.0,
vertical: 0.5,
alignment: const FractionalOffset(0.0, 0.5),
child: new Container(
height: 1.0,
decoration: new BoxDecoration(backgroundColor: const Color(0x80FFFFFF))
......@@ -375,7 +370,7 @@ void main() {
runApp(new MaterialApp(
title: 'Cards',
routes: {
'/': (RouteArguments args) => new CardCollection(navigator: args.navigator),
'/': (RouteArguments args) => new CardCollection(),
}
));
}
......@@ -34,12 +34,10 @@ class DatePickerDemoState extends State<DatePickerDemo> {
child: new Stack([
new Scaffold(
toolBar: new ToolBar(center: new Text("Date Picker")),
body: new Material(
child: new Row(
[new Text(_dateTime.toString())],
alignItems: FlexAlignItems.end,
justifyContent: FlexJustifyContent.center
)
body: new Row(
[new Text(_dateTime.toString())],
alignItems: FlexAlignItems.end,
justifyContent: FlexJustifyContent.center
)
),
new Dialog(
......
......@@ -103,26 +103,24 @@ class DragAndDropAppState extends State<DragAndDropApp> {
toolBar: new ToolBar(
center: new Text('Drag and Drop Flutter Demo')
),
body: new Material(
child: new DefaultTextStyle(
style: Theme.of(context).text.body1.copyWith(textAlign: TextAlign.center),
child: new Column([
new Flexible(child: new Row([
new ExampleDragSource(navigator: config.navigator, name: 'Orange', color: const Color(0xFFFF9000)),
new ExampleDragSource(navigator: config.navigator, name: 'Teal', color: const Color(0xFF00FFFF)),
new ExampleDragSource(navigator: config.navigator, name: 'Yellow', color: const Color(0xFFFFF000)),
],
alignItems: FlexAlignItems.center,
justifyContent: FlexJustifyContent.spaceAround
)),
new Flexible(child: new Row([
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
])),
])
)
body: new DefaultTextStyle(
style: Theme.of(context).text.body1.copyWith(textAlign: TextAlign.center),
child: new Column([
new Flexible(child: new Row([
new ExampleDragSource(navigator: config.navigator, name: 'Orange', color: const Color(0xFFFF9000)),
new ExampleDragSource(navigator: config.navigator, name: 'Teal', color: const Color(0xFF00FFFF)),
new ExampleDragSource(navigator: config.navigator, name: 'Yellow', color: const Color(0xFFFFF000)),
],
alignItems: FlexAlignItems.center,
justifyContent: FlexJustifyContent.spaceAround
)),
new Flexible(child: new Row([
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
new Flexible(child: new ExampleDragTarget()),
])),
])
)
);
}
......
// 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 StatefulComponent {
DropdownDemo();
DropdownDemoState createState() => new DropdownDemoState();
}
class DropdownDemoState extends State<DropdownDemo> {
dynamic _value = 0;
List <DropdownMenuItem> _buildItems() {
return ["One", "Two", "Free", "Four"].map((String label) {
return new DropdownMenuItem(value: label, child: new Text(label));
})
.toList();
}
Widget build(BuildContext context) {
Widget dropdown = new DropdownButton(
items: _buildItems(),
value: _value,
onChanged: (dynamic newValue) {
setState(() {
if (newValue != null)
_value = newValue;
});
}
);
return new Scaffold(
toolBar: new ToolBar(center: new Text('DropdownDemo Demo')),
body: new Container(
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
child: new Center(child: dropdown)
)
);
}
}
void main() {
runApp(new MaterialApp(
title: 'DropdownDemo',
theme: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.blue,
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new DropdownDemo(),
}
));
}
......@@ -6,10 +6,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class IndexedStackDemo extends StatefulComponent {
IndexedStackDemo({ this.navigator });
final NavigatorState navigator;
IndexedStackDemoState createState() => new IndexedStackDemoState();
}
......@@ -23,7 +19,7 @@ class IndexedStackDemoState extends State<IndexedStackDemo> {
});
}
List <PopupMenuItem> _buildMenu(NavigatorState navigator) {
List <PopupMenuItem> _buildMenu() {
TextStyle style = const TextStyle(fontSize: 18.0, fontWeight: bold);
String pad = '';
return new List.generate(_itemCount, (int i) {
......@@ -33,21 +29,18 @@ class IndexedStackDemoState extends State<IndexedStackDemo> {
}
Widget build(BuildContext context) {
List <PopupMenuItem> items = _buildMenu(config.navigator);
List <PopupMenuItem> items = _buildMenu();
IndexedStack indexedStack = new IndexedStack(items, index: _itemIndex, horizontalAlignment: 0.5);
return new Scaffold(
toolBar: new ToolBar(center: new Text('IndexedStackDemo Demo')),
body: new GestureDetector(
onTap: _handleTap,
child: new Container(
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
child: new Center(
child: new Container(
child: indexedStack,
padding: const EdgeDims.all(8.0),
decoration: new BoxDecoration(border: new Border.all(color: Theme.of(context).accentColor))
)
child: new Center(
child: new Container(
child: indexedStack,
padding: const EdgeDims.all(8.0),
decoration: new BoxDecoration(border: new Border.all(color: Theme.of(context).accentColor))
)
)
)
......@@ -64,7 +57,7 @@ void main() {
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new IndexedStackDemo(navigator: args.navigator),
'/': (RouteArguments args) => new IndexedStackDemo(),
}
));
}
......@@ -31,15 +31,15 @@ class Marker extends StatelessComponent {
final double size;
final MarkerType type;
void paintMarker(ui.Canvas canvas, _) {
void paintMarker(PaintingCanvas canvas, _) {
Paint paint = new Paint()..color = const Color(0x8000FF00);
paint.setStyle(ui.PaintingStyle.fill);
double r = size / 2.0;
canvas.drawCircle(new Point(r, r), r, paint);
paint.color = const Color(0xFFFFFFFF);
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 1.0;
paint
..color = const Color(0xFFFFFFFF)
..style = ui.PaintingStyle.stroke
..strokeWidth = 1.0;
if (type == MarkerType.topLeft) {
canvas.drawLine(new Point(r, r), new Point(r + r - 1.0, r), paint);
canvas.drawLine(new Point(r, r), new Point(r, r + r - 1.0), paint);
......@@ -58,7 +58,7 @@ class Marker extends StatelessComponent {
child: new Container(
width: size,
height: size,
child: new CustomPaint(callback: paintMarker)
child: new CustomPaint(onPaint: paintMarker)
)
)
);
......@@ -103,7 +103,7 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
});
}
void handlePointerDown(GlobalKey target, ui.PointerEvent event) {
void handlePointerDown(GlobalKey target, PointerInputEvent event) {
setState(() {
markers[MarkerType.touch] = new Point(event.x, event.y);
final RenderBox box = target.currentContext.findRenderObject();
......@@ -140,7 +140,6 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
toolBar: new ToolBar(center: new Text('Tap a Card')),
body: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
child: new ScrollableMixedWidgetList(
builder: builder,
token: cardModels.length,
......
......@@ -15,10 +15,6 @@ class CardModel {
}
class PageableListApp extends StatefulComponent {
PageableListApp({ this.navigator });
final NavigatorState navigator;
PageableListAppState createState() => new PageableListAppState();
}
......@@ -89,7 +85,7 @@ class PageableListAppState extends State<PageableListApp> {
void _showDrawer() {
showDrawer(
navigator: config.navigator,
context: context,
child: new Block([
new DrawerHeader(child: new Text('Options')),
new DrawerItem(
......@@ -136,11 +132,8 @@ class PageableListAppState extends State<PageableListApp> {
: pageSize.width
);
return new SizeObserver(
callback: updatePageSize,
child: new Container(
child: list,
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50])
)
onSizeChanged: updatePageSize,
child: list
);
}
......@@ -164,7 +157,7 @@ void main() {
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new PageableListApp(navigator: args.navigator),
'/': (RouteArguments args) => new PageableListApp(),
}
));
}
......@@ -17,8 +17,8 @@ class ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
..variable = new AnimatedValue<double>(
0.0,
end: 1.0,
curve: new Interval(0.0, 0.9, curve: ease),
reverseCurve: ease
curve: new Interval(0.0, 0.9, curve: Curves.ease),
reverseCurve: Curves.ease
);
valueAnimation.addStatusListener((PerformanceStatus status) {
if (status == PerformanceStatus.dismissed || status == PerformanceStatus.completed)
......@@ -82,7 +82,6 @@ class ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
onTap: handleTap,
child: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(context).cardColor),
child: new BuilderTransition(
variables: [valueAnimation.variable],
performance: valueAnimation.view,
......
......@@ -60,12 +60,10 @@ class ScaleAppState extends State<ScaleApp> {
child: new Scaffold(
toolBar: new ToolBar(
center: new Text('Scale Demo')),
body: new Material(
child: new GestureDetector(
onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate,
child: new CustomPaint(callback: paint, token: "$_zoom $_offset")
)
body: new GestureDetector(
onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate,
child: new CustomPaint(onPaint: paint, token: "$_zoom $_offset")
)
)
);
......
......@@ -6,10 +6,6 @@ import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
class ScrollbarApp extends StatefulComponent {
ScrollbarApp({ this.navigator });
final NavigatorState navigator;
ScrollbarAppState createState() => new ScrollbarAppState();
}
......@@ -23,7 +19,12 @@ class ScrollbarAppState extends State<ScrollbarApp> {
return new ScrollableList<int>(
items: new List<int>.generate(_itemCount, (int i) => i),
itemExtent: _itemExtent,
itemBuilder: (BuildContext _, int i) => new Text('Item ${dd.format(i)}', style: Theme.of(context).text.title),
itemBuilder: (_, int i) {
return new Text('Item ${dd.format(i)}',
key: new ValueKey<int>(i),
style: Theme.of(context).text.title
);
},
scrollableListPainter: _scrollbarPainter
);
}
......@@ -44,7 +45,6 @@ class ScrollbarAppState extends State<ScrollbarApp> {
return new Scaffold(
toolBar: new ToolBar(center: new Text('Scrollbar Demo')),
body: new Container(
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
padding: new EdgeDims.all(12.0),
child: new Center(child: new Card(child: scrollable))
)
......@@ -61,7 +61,7 @@ void main() {
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new ScrollbarApp(navigator: args.navigator),
'/': (RouteArguments args) => new ScrollbarApp(),
}
));
}
......@@ -68,56 +68,54 @@ class SectorAppState extends State<SectorApp> {
}
Widget buildBody() {
return new Material(
child: new Column(<Widget>[
new Container(
padding: new EdgeDims.symmetric(horizontal: 8.0, vertical: 25.0),
child: new Row(<Widget>[
new RaisedButton(
enabled: _enabledAdd,
child: new IntrinsicWidth(
child: new Row(<Widget>[
new Container(
padding: new EdgeDims.all(4.0),
margin: new EdgeDims.only(right: 10.0),
child: new WidgetToRenderBoxAdapter(sectorAddIcon)
),
new Text('ADD SECTOR'),
])
),
onPressed: addSector
return new Column(<Widget>[
new Container(
padding: new EdgeDims.symmetric(horizontal: 8.0, vertical: 25.0),
child: new Row(<Widget>[
new RaisedButton(
enabled: _enabledAdd,
child: new IntrinsicWidth(
child: new Row(<Widget>[
new Container(
padding: new EdgeDims.all(4.0),
margin: new EdgeDims.only(right: 10.0),
child: new WidgetToRenderBoxAdapter(sectorAddIcon)
),
new Text('ADD SECTOR'),
])
),
new RaisedButton(
enabled: _enabledRemove,
child: new IntrinsicWidth(
child: new Row(<Widget>[
new Container(
padding: new EdgeDims.all(4.0),
margin: new EdgeDims.only(right: 10.0),
child: new WidgetToRenderBoxAdapter(sectorRemoveIcon)
),
new Text('REMOVE SECTOR'),
])
),
onPressed: removeSector
)
],
justifyContent: FlexJustifyContent.spaceAround
)
),
new Flexible(
child: new Container(
margin: new EdgeDims.all(8.0),
decoration: new BoxDecoration(
border: new Border.all(color: new Color(0xFF000000))
onPressed: addSector
),
padding: new EdgeDims.all(8.0),
child: new WidgetToRenderBoxAdapter(sectors)
)
),
],
justifyContent: FlexJustifyContent.spaceBetween
)
new RaisedButton(
enabled: _enabledRemove,
child: new IntrinsicWidth(
child: new Row(<Widget>[
new Container(
padding: new EdgeDims.all(4.0),
margin: new EdgeDims.only(right: 10.0),
child: new WidgetToRenderBoxAdapter(sectorRemoveIcon)
),
new Text('REMOVE SECTOR'),
])
),
onPressed: removeSector
)
],
justifyContent: FlexJustifyContent.spaceAround
)
),
new Flexible(
child: new Container(
margin: new EdgeDims.all(8.0),
decoration: new BoxDecoration(
border: new Border.all(color: new Color(0xFF000000))
),
padding: new EdgeDims.all(8.0),
child: new WidgetToRenderBoxAdapter(sectors)
)
),
],
justifyContent: FlexJustifyContent.spaceBetween
);
}
......
// 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/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
final List<Map<int, Color>> _kColors = [
Colors.amber,
Colors.yellow,
Colors.blue,
Colors.purple,
Colors.indigo,
Colors.deepOrange,
];
class SmoothBlock extends StatefulComponent {
SmoothBlock({ this.color });
final Map<int, Color> color;
SmoothBlockState createState() => new SmoothBlockState();
}
class CardTransition extends StatelessComponent {
CardTransition({
this.child,
this.performance,
this.x,
this.opacity,
this.scale
});
final Widget child;
final Performance performance;
final AnimatedValue<double> x;
final AnimatedValue<double> opacity;
final AnimatedValue<double> scale;
Widget build(BuildContext context) {
return new BuilderTransition(
performance: performance,
variables: [x, opacity, scale],
builder: (BuildContext context) {
Matrix4 transform = new Matrix4.identity()
..translate(x.value)
..scale(scale.value, scale.value);
return new Opacity(
opacity: opacity.value,
child: new Transform(
transform: transform,
child: child
)
);
}
);
}
}
class SmoothBlockState extends State<SmoothBlock> {
double _height = 100.0;
Widget _handleEnter(PerformanceView performance, Widget child) {
return new CardTransition(
x: new AnimatedValue<double>(-200.0, end: 0.0, curve: Curves.ease),
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease),
scale: new AnimatedValue<double>(0.8, end: 1.0, curve: Curves.ease),
performance: performance,
child: child
);
}
Widget _handleExit(PerformanceView performance, Widget child) {
return new CardTransition(
x: new AnimatedValue<double>(0.0, end: 200.0, curve: Curves.ease),
opacity: new AnimatedValue<double>(1.0, end: 0.0, curve: Curves.ease),
scale: new AnimatedValue<double>(1.0, end: 0.8, curve: Curves.ease),
performance: performance,
child: child
);
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: () {
setState(() {
_height = _height == 100.0 ? 200.0 : 100.0;
});
},
child: new EnterExitTransition(
duration: const Duration(milliseconds: 1500),
onEnter: _handleEnter,
onExit: _handleExit,
child: new Container(
key: new ValueKey(_height),
height: _height,
decoration: new BoxDecoration(backgroundColor: config.color[_height.floor() * 4])
)
)
);
}
}
class SmoothResizeDemo extends StatelessComponent {
Widget build(BuildContext context) {
return new Block(_kColors.map((Map<int, Color> color) => new SmoothBlock(color: color)).toList());
}
}
void main() {
runApp(new SmoothResizeDemo());
}
......@@ -96,9 +96,8 @@ class TabbedNavigatorAppState extends State<TabbedNavigatorApp> {
Container _buildCard(BuildContext context, TabNavigator tabNavigator) {
return new Container(
child: new Card(child: new Padding(child: tabNavigator, padding: const EdgeDims.all(8.0))),
padding: const EdgeDims.all(12.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[100])
padding: const EdgeDims.all(12.0),
child: new Card(child: new Padding(child: tabNavigator, padding: const EdgeDims.all(8.0)))
);
}
......
......@@ -9,6 +9,7 @@ library material;
export 'src/material/card.dart';
export 'src/material/checkbox.dart';
export 'src/material/circle_avatar.dart';
export 'src/material/colors.dart';
export 'src/material/constants.dart';
export 'src/material/date_picker.dart';
......@@ -17,17 +18,21 @@ export 'src/material/drawer.dart';
export 'src/material/drawer_divider.dart';
export 'src/material/drawer_header.dart';
export 'src/material/drawer_item.dart';
export 'src/material/dropdown.dart';
export 'src/material/edges.dart';
export 'src/material/flat_button.dart';
export 'src/material/floating_action_button.dart';
export 'src/material/icon_button.dart';
export 'src/material/icon.dart';
export 'src/material/icon_button.dart';
export 'src/material/icon_theme.dart';
export 'src/material/icon_theme_data.dart';
export 'src/material/ink_well.dart';
export 'src/material/input.dart';
export 'src/material/list_item.dart';
export 'src/material/material.dart';
export 'src/material/material_app.dart';
export 'src/material/material_button.dart';
export 'src/material/material_list.dart';
export 'src/material/popup_menu_item.dart';
export 'src/material/popup_menu.dart';
export 'src/material/progress_indicator.dart';
......
......@@ -12,6 +12,7 @@
/// Note: animation.dart depends on the `newton` package.
library painting;
export 'src/painting/basic_types.dart';
export 'src/painting/box_painter.dart';
export 'src/painting/shadows.dart';
export 'src/painting/text_painter.dart';
......
......@@ -6,6 +6,8 @@
library rendering;
export 'src/rendering/auto_layout.dart';
export 'src/rendering/basic_types.dart';
export 'src/rendering/binding.dart';
export 'src/rendering/block.dart';
export 'src/rendering/box.dart';
export 'src/rendering/debug.dart';
......@@ -18,10 +20,10 @@ export 'src/rendering/image.dart';
export 'src/rendering/layer.dart';
export 'src/rendering/node.dart';
export 'src/rendering/object.dart';
export 'src/rendering/overflow.dart';
export 'src/rendering/paragraph.dart';
export 'src/rendering/proxy_box.dart';
export 'src/rendering/shifted_box.dart';
export 'src/rendering/binding.dart';
export 'src/rendering/stack.dart';
export 'src/rendering/statistics_box.dart';
export 'src/rendering/toggleable.dart';
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show Color, Rect;
import 'dart:ui' show Color, Size, Rect;
import 'curves.dart';
......@@ -104,6 +104,17 @@ class AnimatedColorValue extends AnimatedValue<Color> {
Color lerp(double t) => Color.lerp(begin, end, t);
}
/// An animated variable containing a rectangle
///
/// This class specializes the interpolation of AnimatedValue<Rect> to be
/// appropriate for rectangles.
class AnimatedSizeValue extends AnimatedValue<Size> {
AnimatedSizeValue(Size begin, { Size end, Curve curve, Curve reverseCurve })
: super(begin, end: end, curve: curve, reverseCurve: reverseCurve);
Size lerp(double t) => Size.lerp(begin, end, t);
}
/// An animated variable containing a rectangle
///
/// This class specializes the interpolation of AnimatedValue<Rect> to be
......
......@@ -29,7 +29,7 @@ class Linear implements Curve {
/// A curve that is 0.0 until start, then curved from 0.0 to 1.0 at end, then 1.0
class Interval implements Curve {
const Interval(this.start, this.end, { this.curve: linear });
const Interval(this.start, this.end, { this.curve: Curves.linear });
/// The smallest value for which this interval is 0.0
final double start;
......@@ -153,38 +153,43 @@ class ElasticInOutCurve implements Curve {
}
}
/// A linear animation curve
const Linear linear = const Linear();
/// A collection of common animation curves.
class Curves {
Curves._();
/// A cubic animation curve that speeds up quickly and ends slowly
const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0);
/// A linear animation curve
static const Linear linear = const Linear();
/// A cubic animation curve that starts slowly and ends quickly
const Cubic easeIn = const Cubic(0.42, 0.0, 1.0, 1.0);
/// A cubic animation curve that speeds up quickly and ends slowly
static const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0);
/// A cubic animation curve that starts quickly and ends slowly
const Cubic easeOut = const Cubic(0.0, 0.0, 0.58, 1.0);
/// A cubic animation curve that starts slowly and ends quickly
static const Cubic easeIn = const Cubic(0.42, 0.0, 1.0, 1.0);
/// A cubic animation curve that starts slowly, speeds up, and then and ends slowly
const Cubic easeInOut = const Cubic(0.42, 0.0, 0.58, 1.0);
/// A cubic animation curve that starts quickly and ends slowly
static const Cubic easeOut = const Cubic(0.0, 0.0, 0.58, 1.0);
/// An oscillating curve that grows in magnitude
const BounceInCurve bounceIn = const BounceInCurve();
/// A cubic animation curve that starts slowly, speeds up, and then and ends slowly
static const Cubic easeInOut = const Cubic(0.42, 0.0, 0.58, 1.0);
/// An oscillating curve that first grows and then shrink in magnitude
const BounceOutCurve bounceOut = const BounceOutCurve();
/// An oscillating curve that grows in magnitude
static const BounceInCurve bounceIn = const BounceInCurve();
/// An oscillating curve that first grows and then shrink in magnitude
const BounceInOutCurve bounceInOut = const BounceInOutCurve();
/// An oscillating curve that first grows and then shrink in magnitude
static const BounceOutCurve bounceOut = const BounceOutCurve();
/// An oscillating curve that grows in magnitude while overshootings its bounds
const ElasticInCurve elasticIn = const ElasticInCurve();
/// An oscillating curve that first grows and then shrink in magnitude
static const BounceInOutCurve bounceInOut = const BounceInOutCurve();
/// An oscillating curve that shrinks in magnitude while overshootings its bounds
const ElasticOutCurve elasticOut = const ElasticOutCurve();
/// An oscillating curve that grows in magnitude while overshootings its bounds
static const ElasticInCurve elasticIn = const ElasticInCurve();
/// An oscillating curve that grows and then shrinks in magnitude while overshootings its bounds
const ElasticInOutCurve elasticInOut = const ElasticInOutCurve();
/// An oscillating curve that shrinks in magnitude while overshootings its bounds
static const ElasticOutCurve elasticOut = const ElasticOutCurve();
/// A curve that starts quickly and eases into its final position. Over the course of the animation, the object spends more time near its final destination. As a result, the user isn’t left waiting for the animation to finish, and the negative effects of motion are minimized.
const Curve fastOutSlowIn = const Cubic(0.4, 0.0, 0.2, 1.0);
/// An oscillating curve that grows and then shrinks in magnitude while overshootings its bounds
static const ElasticInOutCurve elasticInOut = const ElasticInOutCurve();
/// A curve that starts quickly and eases into its final position. Over the course of the animation, the object spends more time near its final destination. As a result, the user isn’t left waiting for the animation to finish, and the negative effects of motion are minimized.
static const Curve fastOutSlowIn = const Cubic(0.4, 0.0, 0.2, 1.0);
}
......@@ -31,6 +31,8 @@ typedef void PerformanceStatusListener(PerformanceStatus status);
/// want to watch a performance but should not be able to change the
/// performance's state.
abstract class PerformanceView {
const PerformanceView();
/// Update the given variable according to the current progress of the performance
void updateVariable(Animatable variable);
/// Calls the listener every time the progress of the performance changes
......@@ -42,9 +44,23 @@ abstract class PerformanceView {
/// Stops calling the listener every time the status of the performance changes
void removeStatusListener(PerformanceStatusListener listener);
/// The current status of this animation
/// The current status of this animation.
PerformanceStatus get status;
/// The current direction of the animation.
AnimationDirection get direction;
/// The direction used to select the current curve.
///
/// The curve direction is only reset when we hit the beginning or the end of
/// the timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
AnimationDirection get curveDirection;
/// The current progress of this animation (a value from 0.0 to 1.0).
/// This is the value that is used to update any variables when using updateVariable().
double get progress;
/// Whether this animation is stopped at the beginning
bool get isDismissed => status == PerformanceStatus.dismissed;
......@@ -52,6 +68,85 @@ abstract class PerformanceView {
bool get isCompleted => status == PerformanceStatus.completed;
}
class AlwaysCompletePerformance extends PerformanceView {
const AlwaysCompletePerformance();
void updateVariable(Animatable variable) {
variable.setProgress(1.0, AnimationDirection.forward);
}
// this performance never changes state
void addListener(PerformanceListener listener) { }
void removeListener(PerformanceListener listener) { }
void addStatusListener(PerformanceStatusListener listener) { }
void removeStatusListener(PerformanceStatusListener listener) { }
PerformanceStatus get status => PerformanceStatus.completed;
AnimationDirection get direction => AnimationDirection.forward;
AnimationDirection get curveDirection => AnimationDirection.forward;
double get progress => 1.0;
}
const AlwaysCompletePerformance alwaysCompletePerformance = const AlwaysCompletePerformance();
class ReversePerformance extends PerformanceView {
ReversePerformance(this.masterPerformance) {
masterPerformance.addStatusListener(_statusChangeHandler);
}
final PerformanceView masterPerformance;
void updateVariable(Animatable variable) {
variable.setProgress(progress, curveDirection);
}
void addListener(PerformanceListener listener) {
masterPerformance.addListener(listener);
}
void removeListener(PerformanceListener listener) {
masterPerformance.removeListener(listener);
}
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
/// Calls listener every time the status of this performance changes
void addStatusListener(PerformanceStatusListener listener) {
_statusListeners.add(listener);
}
/// Stops calling the listener every time the status of this performance changes
void removeStatusListener(PerformanceStatusListener listener) {
_statusListeners.remove(listener);
}
void _statusChangeHandler(PerformanceStatus status) {
status = _reverseStatus(status);
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
for (PerformanceStatusListener listener in localListeners)
listener(status);
}
PerformanceStatus get status => _reverseStatus(masterPerformance.status);
AnimationDirection get direction => _reverseDirection(masterPerformance.direction);
AnimationDirection get curveDirection => _reverseDirection(masterPerformance.curveDirection);
double get progress => 1.0 - masterPerformance.progress;
PerformanceStatus _reverseStatus(PerformanceStatus status) {
switch (status) {
case PerformanceStatus.forward: return PerformanceStatus.reverse;
case PerformanceStatus.reverse: return PerformanceStatus.forward;
case PerformanceStatus.completed: return PerformanceStatus.dismissed;
case PerformanceStatus.dismissed: return PerformanceStatus.completed;
}
}
AnimationDirection _reverseDirection(AnimationDirection direction) {
switch (direction) {
case AnimationDirection.forward: return AnimationDirection.reverse;
case AnimationDirection.reverse: return AnimationDirection.forward;
}
}
}
/// A timeline that can be reversed and used to update [Animatable]s.
///
/// For example, a performance may handle an animation of a menu opening by
......@@ -61,12 +156,16 @@ abstract class PerformanceView {
/// [fling] the timeline causing a physics-based simulation to take over the
/// progression.
class Performance extends PerformanceView {
Performance({ this.duration, double progress }) {
Performance({ this.duration, double progress, this.debugLabel }) {
_timeline = new SimulationStepper(_tick);
if (progress != null)
_timeline.value = progress.clamp(0.0, 1.0);
}
/// A label that is used in the toString() output. Intended to aid with
/// identifying performance instances in debug output.
final String debugLabel;
/// Returns a [PerformanceView] for this performance,
/// so that a pointer to this object can be passed around without
/// allowing users of that pointer to mutate the AnimationPerformance state.
......@@ -76,13 +175,9 @@ class Performance extends PerformanceView {
Duration duration;
SimulationStepper _timeline;
AnimationDirection get direction => _direction;
AnimationDirection _direction;
/// The direction used to select the current curve
///
/// Curve direction is only reset when we hit the beginning or the end of the
/// timeline to avoid discontinuities in the value of any variables this
/// performance is used to animate.
AnimationDirection get curveDirection => _curveDirection;
AnimationDirection _curveDirection;
/// If non-null, animate with this timing instead of a linear timing
......@@ -93,7 +188,6 @@ class Performance extends PerformanceView {
/// Note: Setting this value stops the current animation.
double get progress => _timeline.value.clamp(0.0, 1.0);
void set progress(double t) {
// TODO(mpcomplete): should this affect |direction|?
stop();
_timeline.value = t.clamp(0.0, 1.0);
_checkStatusChanged();
......@@ -220,6 +314,12 @@ class Performance extends PerformanceView {
_notifyListeners();
_checkStatusChanged();
}
String toString() {
if (debugLabel != null)
return '$runtimeType at $progress for $debugLabel';
return '$runtimeType at $progress';
}
}
/// An animation performance with an animated variable with a concrete type
......
......@@ -16,6 +16,13 @@ double timeDilation = 1.0;
/// common time base.
typedef void SchedulerCallback(Duration timeStamp);
typedef void SchedulerExceptionHandler(dynamic exception, StackTrace stack);
/// This callback is invoked whenever an exception is caught by the scheduler.
/// The 'exception' argument contains the object that was thrown, and the
/// 'stack' argument contains the stack trace. If the callback is set, it is
/// invoked instead of printing the information to the console.
SchedulerExceptionHandler debugSchedulerExceptionHandler;
/// Schedules callbacks to run in concert with the engine's animation system
class Scheduler {
/// Requires clients to use the [scheduler] singleton
......@@ -24,35 +31,66 @@ class Scheduler {
}
bool _haveScheduledVisualUpdate = false;
int _nextCallbackId = 1;
int _nextPrivateCallbackId = 0; // negative
int _nextCallbackId = 0; // positive
final List<SchedulerCallback> _persistentCallbacks = new List<SchedulerCallback>();
Map<int, SchedulerCallback> _transientCallbacks = new LinkedHashMap<int, SchedulerCallback>();
final Set<int> _removedIds = new Set<int>();
final List<SchedulerCallback> _postFrameCallbacks = new List<SchedulerCallback>();
bool _inFrame = false;
int get transientCallbackCount => _transientCallbacks.length;
/// Called by the engine to produce a new frame.
///
/// This function first calls all the callbacks registered by
/// [requestAnimationFrame] and then calls all the callbacks registered by
/// [addPersistentFrameCallback], which typically drive the rendering pipeline.
void beginFrame(double timeStampMS) {
timeStampMS /= timeDilation;
Duration timeStamp = new Duration(microseconds: (timeStampMS * Duration.MICROSECONDS_PER_MILLISECOND).round());
/// [requestAnimationFrame], then calls all the callbacks registered by
/// [addPersistentFrameCallback], which typically drive the rendering pipeline,
/// and finally calls the callbacks registered by [requestPostFrameCallback].
void beginFrame(double rawTimeStamp) {
assert(!_inFrame);
_inFrame = true;
rawTimeStamp /= timeDilation;
final Duration timeStamp = new Duration(
microseconds: (rawTimeStamp * Duration.MICROSECONDS_PER_MILLISECOND).round()
);
_haveScheduledVisualUpdate = false;
assert(_postFrameCallbacks.length == 0);
Map<int, SchedulerCallback> callbacks = _transientCallbacks;
_transientCallbacks = new Map<int, SchedulerCallback>();
callbacks.forEach((int id, SchedulerCallback callback) {
if (!_removedIds.contains(id))
callback(timeStamp);
invokeCallback(callback, timeStamp);
});
_removedIds.clear();
for (SchedulerCallback callback in _persistentCallbacks)
invokeCallback(callback, timeStamp);
for (SchedulerCallback callback in _postFrameCallbacks)
invokeCallback(callback, timeStamp);
_postFrameCallbacks.clear();
_inFrame = false;
}
void invokeCallback(SchedulerCallback callback, Duration timeStamp) {
assert(callback != null);
try {
callback(timeStamp);
} catch (exception, stack) {
if (debugSchedulerExceptionHandler != null) {
debugSchedulerExceptionHandler(exception, stack);
} else {
print('-- EXCEPTION IN SCHEDULER CALLBACK --');
print('$exception');
print('Stack trace:');
print('$stack');
}
}
}
/// Call callback every frame.
......@@ -70,20 +108,42 @@ class Scheduler {
/// is passed a timeStamp that you can use to determine how far along the
/// timeline to advance your animation.
///
/// Callbacks in invoked in an arbitrary order.
///
/// Returns an id that can be used to unschedule this callback.
int requestAnimationFrame(SchedulerCallback callback) {
int id = _nextCallbackId++;
_transientCallbacks[id] = callback;
_nextCallbackId += 1;
_transientCallbacks[_nextCallbackId] = callback;
ensureVisualUpdate();
return id;
return _nextCallbackId;
}
/// Cancel the callback identified by id.
void cancelAnimationFrame(int id) {
assert(id > 0);
_transientCallbacks.remove(id);
_removedIds.add(id);
}
/// Schedule a callback for the end of this frame.
///
/// If a frame is in progress, the callback will be run just after the main
/// rendering pipeline has been flushed. In this case, order is preserved (the
/// callbacks are run in registration order).
///
/// If no frame is in progress, it will be called at the start of the next
/// frame. In this case, the registration order is not preserved. Callbacks
/// are called in an arbitrary order.
void requestPostFrameCallback(SchedulerCallback callback) {
if (_inFrame) {
_postFrameCallbacks.add(callback);
} else {
_nextPrivateCallbackId -= 1;
_transientCallbacks[_nextPrivateCallbackId] = callback;
ensureVisualUpdate();
}
}
/// Ensure that a frame will be produced after this function is called.
void ensureVisualUpdate() {
if (_haveScheduledVisualUpdate)
......
......@@ -66,7 +66,7 @@ class SimulationStepper {
///
/// Returns a future that resolves when the timeline stops animating,
/// typically when the timeline arives at the target value.
Future animateTo(double target, { Duration duration, Curve curve: linear }) {
Future animateTo(double target, { Duration duration, Curve curve: Curves.linear }) {
assert(duration > Duration.ZERO);
assert(!isAnimating);
return _start(new _TweenSimulation(value, target, duration, curve));
......
......@@ -24,28 +24,28 @@ class PointerInputEvent extends InputEvent {
const PointerInputEvent({
String type,
double timeStamp: 0.0,
this.pointer,
this.pointer: 0,
this.kind,
this.x,
this.y,
this.dx,
this.dy,
this.buttons,
this.down,
this.primary,
this.obscured,
this.pressure,
this.pressureMin,
this.pressureMax,
this.distance,
this.distanceMin,
this.distanceMax,
this.radiusMajor,
this.radiusMinor,
this.radiusMin,
this.radiusMax,
this.orientation,
this.tilt
this.x: 0.0,
this.y: 0.0,
this.dx: 0.0,
this.dy: 0.0,
this.buttons: 0,
this.down: false,
this.primary: false,
this.obscured: false,
this.pressure: 0.0,
this.pressureMin: 0.0,
this.pressureMax: 0.0,
this.distance: 0.0,
this.distanceMin: 0.0,
this.distanceMax: 0.0,
this.radiusMajor: 0.0,
this.radiusMinor: 0.0,
this.radiusMin: 0.0,
this.radiusMax: 0.0,
this.orientation: 0.0,
this.tilt: 0.0
}) : super(type: type, timeStamp: timeStamp);
final int pointer;
......
......@@ -12,8 +12,8 @@ import 'theme.dart';
export 'package:flutter/rendering.dart' show ValueChanged;
const double _kMidpoint = 0.5;
const ui.Color _kLightUncheckedColor = const ui.Color(0x8A000000);
const ui.Color _kDarkUncheckedColor = const ui.Color(0xB2FFFFFF);
const Color _kLightUncheckedColor = const Color(0x8A000000);
const Color _kDarkUncheckedColor = const Color(0xB2FFFFFF);
const double _kEdgeSize = 18.0;
const double _kEdgeRadius = 1.0;
const double _kStrokeWidth = 2.0;
......@@ -126,7 +126,7 @@ class _RenderCheckbox extends RenderToggleable {
void paint(PaintingContext context, Offset offset) {
final PaintingCanvas canvas = context.canvas;
// Choose a color between grey and the theme color
ui.Paint paint = new ui.Paint()
Paint paint = new Paint()
..strokeWidth = _kStrokeWidth
..color = uncheckedColor;
......@@ -134,27 +134,27 @@ class _RenderCheckbox extends RenderToggleable {
// Because we have a stroke size of 2, we should have a minimum 1.0 inset.
double inset = 2.0 - (position - _kMidpoint).abs() * 2.0;
double rectSize = _kEdgeSize - inset * _kStrokeWidth;
ui.Rect rect =
new ui.Rect.fromLTWH(offset.dx + inset, offset.dy + inset, rectSize, rectSize);
Rect rect = new Rect.fromLTWH(offset.dx + inset, offset.dy + inset, rectSize, rectSize);
// Create an inner rectangle to cover inside of rectangle. This is needed to avoid
// painting artefacts caused by overlayed paintings.
ui.Rect innerRect = rect.deflate(1.0);
Rect innerRect = rect.deflate(1.0);
ui.RRect rrect = new ui.RRect()
..setRectXY(rect, _kEdgeRadius, _kEdgeRadius);
// Outline of the empty rrect
paint.setStyle(ui.PaintingStyle.stroke);
paint.style = ui.PaintingStyle.stroke;
canvas.drawRRect(rrect, paint);
// Radial gradient that changes size
if (position > 0) {
paint.setStyle(ui.PaintingStyle.fill);
paint.setShader(new ui.Gradient.radial(
paint
..style = ui.PaintingStyle.fill
..shader = new ui.Gradient.radial(
new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
_kEdgeSize * (_kMidpoint - position) * 8.0, <Color>[
const ui.Color(0x00000000),
const Color(0x00000000),
uncheckedColor
]));
]);
canvas.drawRect(innerRect, paint);
}
......@@ -162,24 +162,25 @@ class _RenderCheckbox extends RenderToggleable {
double t = (position - _kMidpoint) / (1.0 - _kMidpoint);
// First draw a rounded rect outline then fill inner rectangle with accent color.
paint.color = new Color.fromARGB((t * 255).floor(), _accentColor.red,
_accentColor.green, _accentColor.blue);
paint.setStyle(ui.PaintingStyle.stroke);
paint
..color = new Color.fromARGB((t * 255).floor(), _accentColor.red, _accentColor.green, _accentColor.blue)
..style = ui.PaintingStyle.stroke;
canvas.drawRRect(rrect, paint);
paint.setStyle(ui.PaintingStyle.fill);
paint.style = ui.PaintingStyle.fill;
canvas.drawRect(innerRect, paint);
// White inner check
paint.color = const ui.Color(0xFFFFFFFF);
paint.setStyle(ui.PaintingStyle.stroke);
ui.Path path = new ui.Path();
ui.Point start = new ui.Point(_kEdgeSize * 0.15, _kEdgeSize * 0.45);
ui.Point mid = new ui.Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
ui.Point end = new ui.Point(_kEdgeSize * 0.85, _kEdgeSize * 0.25);
paint
..color = const Color(0xFFFFFFFF)
..style = ui.PaintingStyle.stroke;
Path path = new Path();
Point start = new Point(_kEdgeSize * 0.15, _kEdgeSize * 0.45);
Point mid = new Point(_kEdgeSize * 0.4, _kEdgeSize * 0.7);
Point end = new Point(_kEdgeSize * 0.85, _kEdgeSize * 0.25);
Point lerp(Point p1, Point p2, double t) =>
new Point(p1.x * (1.0 - t) + p2.x * t, p1.y * (1.0 - t) + p2.y * t);
ui.Point drawStart = lerp(start, mid, 1.0 - t);
ui.Point drawEnd = lerp(mid, end, t);
Point drawStart = lerp(start, mid, 1.0 - t);
Point drawEnd = lerp(mid, end, t);
path.moveTo(offset.dx + drawStart.x, offset.dy + drawStart.y);
path.lineTo(offset.dx + mid.x, offset.dy + mid.y);
path.lineTo(offset.dx + drawEnd.x, offset.dy + drawEnd.y);
......
// 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/painting.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'theme.dart';
import 'typography.dart';
class CircleAvatar extends StatelessComponent {
CircleAvatar({
Key key,
this.label,
this.backgroundColor,
this.textTheme
}) : super(key: key);
final String label;
final Color backgroundColor;
final TextTheme textTheme;
Widget build(BuildContext context) {
Color color = backgroundColor;
TextStyle style = textTheme?.title;
if (color == null || style == null) {
ThemeData themeData = Theme.of(context);
color ??= themeData.primaryColor;
style ??= themeData.primaryTextTheme.title;
}
return new AnimatedContainer(
duration: kThemeChangeDuration,
decoration: new BoxDecoration(
backgroundColor: color,
shape: Shape.circle
),
width: 40.0,
height: 40.0,
child: new Center(
child: new Text(label, style: style)
)
);
}
}
......@@ -19,7 +19,11 @@ const double kSnackBarHeight = 52.0;
// https://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
const double kListTitleHeight = 72.0;
const double kListSubtitleHeight = 48.0;
const double kListItemHeight = 72.0;
const double kOneLineListItemHeight = 48.0;
const double kOneLineListItemWithAvatarHeight = 56.0;
const double kTwoLineListItemHeight = 72.0;
const double kThreeLineListItemHeight = 88.0;
const double kMaterialDrawerHeight = 140.0;
const double kScrollbarSize = 10.0;
......
......@@ -6,7 +6,6 @@ import 'dart:async';
import 'package:intl/date_symbols.dart';
import 'package:intl/intl.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
......@@ -123,17 +122,15 @@ class _DatePickerHeader extends StatelessComponent {
Widget build(BuildContext context) {
ThemeData theme = Theme.of(context);
TextTheme headerTheme;
TextTheme headerTheme = theme.primaryTextTheme;
Color dayColor;
Color yearColor;
switch(theme.primaryColorBrightness) {
case ThemeBrightness.light:
headerTheme = Typography.black;
dayColor = mode == DatePickerMode.day ? Colors.black87 : Colors.black54;
yearColor = mode == DatePickerMode.year ? Colors.black87 : Colors.black54;
break;
case ThemeBrightness.dark:
headerTheme = Typography.white;
dayColor = mode == DatePickerMode.day ? Colors.white : Colors.white70;
yearColor = mode == DatePickerMode.year ? Colors.white : Colors.white70;
break;
......
......@@ -5,7 +5,6 @@
import 'dart:async';
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -140,11 +139,11 @@ class _DialogRoute extends PerformanceRoute {
bool get opaque => false;
Duration get transitionDuration => const Duration(milliseconds: 150);
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
Widget build(RouteArguments args) {
return new FadeTransition(
performance: performance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
child: builder(new RouteArguments(navigator: navigator, previousPerformance: this.performance, nextPerformance: nextRoutePerformance))
performance: args.previousPerformance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.easeOut),
child: builder(args)
);
}
......@@ -154,15 +153,15 @@ class _DialogRoute extends PerformanceRoute {
}
}
Future showDialog(NavigatorState navigator, DialogBuilder builder) {
Future showDialog({ BuildContext context, Widget child }) {
Completer completer = new Completer();
navigator.push(new _DialogRoute(
Navigator.of(context).push(new _DialogRoute(
completer: completer,
builder: (RouteArguments args) {
return new Focus(
key: new GlobalObjectKey(completer),
autofocus: true,
child: builder(args.navigator)
child: child
);
}
));
......
......@@ -83,7 +83,7 @@ class _Drawer extends StatelessComponent {
performance: performance,
position: new AnimatedValue<Point>(_kClosedPosition, end: _kOpenPosition),
child: new AnimatedContainer(
curve: ease,
curve: Curves.ease,
duration: _kThemeChangeDuration,
decoration: new BoxDecoration(
backgroundColor: Theme.of(context).canvasColor,
......@@ -106,13 +106,13 @@ class _DrawerRoute extends Route {
final int level;
PerformanceView get performance => _performance?.view;
Performance _performance = new Performance(duration: _kBaseSettleDuration);
Performance _performance = new Performance(duration: _kBaseSettleDuration, debugLabel: 'Drawer');
bool get opaque => false;
bool _interactive = true;
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
Widget build(RouteArguments args) {
return new Focus(
key: new GlobalObjectKey(this),
autofocus: true,
......@@ -169,7 +169,6 @@ class _DrawerRoute extends Route {
}
}
void showDrawer({ NavigatorState navigator, Widget child, int level: 3 }) {
assert(navigator != null);
navigator.push(new _DrawerRoute(child: child, level: level));
void showDrawer({ BuildContext context, Widget child, int level: 3 }) {
Navigator.of(context).push(new _DrawerRoute(child: child, level: level));
}
......@@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -49,10 +45,10 @@ class _DrawerItemState extends State<DrawerItem> {
return Colors.transparent;
}
ui.ColorFilter _getColorFilter(ThemeData themeData) {
ColorFilter _getColorFilter(ThemeData themeData) {
if (config.selected)
return new ui.ColorFilter.mode(themeData.primaryColor, ui.TransferMode.srcATop);
return new ui.ColorFilter.mode(const Color(0x73000000), ui.TransferMode.dstIn);
return new ColorFilter.mode(themeData.primaryColor, TransferMode.srcATop);
return new ColorFilter.mode(const Color(0x73000000), TransferMode.dstIn);
}
Widget build(BuildContext context) {
......
// 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;
import 'package:flutter/animation.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'icon.dart';
import 'ink_well.dart';
import 'shadows.dart';
import 'theme.dart';
const Duration _kMenuDuration = const Duration(milliseconds: 300);
const double _kMenuItemHeight = 48.0;
const double _kMenuHorizontalPadding = 36.0;
const double _kBaselineOffsetFromBottom = 20.0;
const Border _kDropdownUnderline = const Border(bottom: const BorderSide(color: const Color(0xFFBDBDBD), width: 2.0));
class _DropdownMenu extends StatelessComponent {
_DropdownMenu({
Key key,
this.items,
this.rect,
this.performance,
this.selectedIndex,
this.level: 4
}) : super(key: key) {
assert(items != null);
assert(performance != null);
}
final List<DropdownMenuItem> items;
final Rect rect;
final PerformanceView performance;
final int selectedIndex;
final int level;
Widget build(BuildContext context) {
// The menu is shown in three stages (unit timing in brackets):
// [0 - 0.25] - Fade in a rect-sized menu container with the selected item.
// [0.25 - 0.5] - Grow the otherwise empty menu container from the center
// until it's big enough for as many items as we're going to show.
// [0.5 - 1.0] Fade in the remaining visible items from top to bottom.
//
// When the menu is dismissed we just fade the entire thing out
// in the first 0.25.
final double unit = 0.5 / (items.length + 1.5);
final List<Widget> children = <Widget>[];
for (int itemIndex = 0; itemIndex < items.length; ++itemIndex) {
AnimatedValue<double> opacity;
if (itemIndex == selectedIndex) {
opacity = new AnimatedValue<double>(0.0, end: 1.0, curve: const Interval(0.0, 0.001), reverseCurve: const Interval(0.75, 1.0));
} else {
final double start = (0.5 + (itemIndex + 1) * unit).clamp(0.0, 1.0);
final double end = (start + 1.5 * unit).clamp(0.0, 1.0);
opacity = new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end), reverseCurve: const Interval(0.75, 1.0));
}
children.add(new FadeTransition(
performance: performance,
opacity: opacity,
child: new InkWell(
child: items[itemIndex],
onTap: () {
Navigator.of(context).pop(items[itemIndex].value);
}
)
));
}
final AnimatedValue<double> menuOpacity = new AnimatedValue<double>(0.0,
end: 1.0,
curve: new Interval(0.0, 0.25),
reverseCurve: new Interval(0.75, 1.0)
);
final AnimatedValue<double> menuTop = new AnimatedValue<double>(rect.top,
end: rect.top - selectedIndex * rect.height,
curve: new Interval(0.25, 0.5),
reverseCurve: const Interval(0.0, 0.001)
);
final AnimatedValue<double> menuBottom = new AnimatedValue<double>(rect.bottom,
end: menuTop.end + items.length * rect.height,
curve: new Interval(0.25, 0.5),
reverseCurve: const Interval(0.0, 0.001)
);
final BoxPainter menuPainter = new BoxPainter(new BoxDecoration(
backgroundColor: Theme.of(context).canvasColor,
borderRadius: 2.0,
boxShadow: shadows[level]
));
return new FadeTransition(
performance: performance,
opacity: menuOpacity,
child: new BuilderTransition(
performance: performance,
variables: <AnimatedValue<double>>[menuTop, menuBottom],
builder: (BuildContext context) {
RenderBox renderBox = context.findRenderObject();
return new CustomPaint(
child: new ScrollableViewport(child: new Container(child: new Column(children))),
onPaint: (ui.Canvas canvas, Size size) {
double top = renderBox.globalToLocal(new Point(0.0, menuTop.value)).y;
double bottom = renderBox.globalToLocal(new Point(0.0, menuBottom.value)).y;
menuPainter.paint(canvas, new Rect.fromLTRB(0.0, top, size.width, bottom));
}
);
}
)
);
}
}
class _MenuRoute extends PerformanceRoute {
_MenuRoute({
this.completer,
this.items,
this.selectedIndex,
this.rect,
this.level: 4
});
final Completer completer;
final Rect rect;
final List<DropdownMenuItem> items;
final int level;
final int selectedIndex;
bool get ephemeral => true;
bool get modal => true;
bool get opaque => false;
Duration get transitionDuration => _kMenuDuration;
Widget build(RouteArguments args) {
final Size navigatorSize = navigator.context.findRenderObject().size;
final RelativeRect menuRect = new RelativeRect.fromSize(rect, navigatorSize);
return new Positioned(
top: menuRect.top - (selectedIndex * rect.height),
right: menuRect.right - _kMenuHorizontalPadding,
left: menuRect.left - _kMenuHorizontalPadding,
child: new Focus(
key: new GlobalObjectKey(this),
autofocus: true,
child: new _DropdownMenu(
items: items,
selectedIndex: selectedIndex,
rect: rect,
level: level,
performance: performance
)
)
);
}
void didPop([dynamic result]) {
completer.complete(result);
super.didPop(result);
}
}
class DropdownMenuItem extends StatelessComponent {
DropdownMenuItem({
Key key,
this.value,
this.child
}) : super(key: key);
final Widget child;
final dynamic value;
Widget build(BuildContext context) {
return new Container(
height: _kMenuItemHeight,
padding: const EdgeDims.only(left: 8.0, right: 8.0, top: 6.0),
child: new DefaultTextStyle(
style: Theme.of(context).text.subhead,
child: new Baseline(
baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom,
child: child
)
)
);
}
}
class DropdownButton extends StatelessComponent {
DropdownButton({
Key key,
this.items,
this.value,
this.onChanged,
this.level: 4
}) : super(key: key);
final List<DropdownMenuItem> items;
final dynamic value;
final ValueChanged onChanged;
final int level;
void _showDropdown(BuildContext context, int selectedIndex, GlobalKey indexedStackKey) {
final RenderBox renderBox = indexedStackKey.currentContext.findRenderObject();
final Rect rect = renderBox.localToGlobal(Point.origin) & renderBox.size;
final Completer completer = new Completer();
Navigator.of(context).push(new _MenuRoute(
completer: completer,
items: items,
selectedIndex: selectedIndex,
rect: rect,
level: level
));
completer.future.then((dynamic newValue) {
if (onChanged != null)
onChanged(newValue);
});
}
Widget build(BuildContext context) {
GlobalKey indexedStackKey = new GlobalKey(label: 'DropdownButton.IndexedStack');
int selectedIndex = 0;
for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
if (items[itemIndex].value == value) {
selectedIndex = itemIndex;
break;
}
}
return new GestureDetector(
child: new Container(
decoration: new BoxDecoration(border: _kDropdownUnderline),
child: new IntrinsicWidth(
child: new Row(<Widget>[
new IndexedStack(items,
key: indexedStackKey,
index: selectedIndex,
horizontalAlignment: 0.5
),
new Container(
child: new Icon(type: 'navigation/arrow_drop_down', size: 36),
padding: const EdgeDims.only(top: 6.0)
)
])
)
),
onTap: () {
_showDropdown(context, selectedIndex, indexedStackKey);
}
);
}
}
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......
......@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'icon.dart';
import 'icon_theme.dart';
import 'icon_theme_data.dart';
import 'ink_well.dart';
import 'material.dart';
import 'theme.dart';
......
......@@ -2,50 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'theme.dart';
enum IconThemeColor { white, black }
class IconThemeData {
const IconThemeData({ this.color });
final IconThemeColor color;
bool operator ==(dynamic other) {
if (other is! IconThemeData)
return false;
final IconThemeData typedOther = other;
return color == typedOther;
}
int get hashCode => color.hashCode;
}
class IconTheme extends InheritedWidget {
IconTheme({
Key key,
this.data,
Widget child
}) : super(key: key, child: child) {
assert(data != null);
assert(child != null);
}
final IconThemeData data;
static IconThemeData of(BuildContext context) {
IconTheme result = context.inheritedWidgetOfType(IconTheme);
return result?.data;
}
bool updateShouldNotify(IconTheme old) => data != old.data;
}
import 'icon_theme.dart';
import 'icon_theme_data.dart';
AssetBundle _initIconBundle() {
if (rootBundle != null)
......@@ -63,12 +25,15 @@ class Icon extends StatelessComponent {
this.type: '',
this.color,
this.colorFilter
}) : super(key: key);
}) : super(key: key) {
assert(size != null);
assert(type != null);
}
final int size;
final String type;
final IconThemeColor color;
final ui.ColorFilter colorFilter;
final ColorFilter colorFilter;
String _getColorSuffix(BuildContext context) {
IconThemeColor iconThemeColor = color;
......@@ -108,4 +73,10 @@ class Icon extends StatelessComponent {
colorFilter: colorFilter
);
}
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$type');
description.add('size: $size');
}
}
......@@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'icon.dart';
import 'icon_theme_data.dart';
class IconButton extends StatelessComponent {
const IconButton({
......@@ -20,7 +18,7 @@ class IconButton extends StatelessComponent {
final String icon;
final IconThemeColor color;
final ui.ColorFilter colorFilter;
final ColorFilter colorFilter;
final GestureTapCallback onPressed;
Widget build(BuildContext context) {
......@@ -37,4 +35,9 @@ class IconButton extends StatelessComponent {
)
);
}
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$icon');
}
}
// 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 'icon_theme_data.dart';
class IconTheme extends InheritedWidget {
IconTheme({
Key key,
this.data,
Widget child
}) : super(key: key, child: child) {
assert(data != null);
assert(child != null);
}
final IconThemeData data;
static IconThemeData of(BuildContext context) {
IconTheme result = context.inheritedWidgetOfType(IconTheme);
return result?.data;
}
bool updateShouldNotify(IconTheme old) => data != old.data;
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$data');
}
}
// 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.
enum IconThemeColor { white, black }
class IconThemeData {
const IconThemeData({ this.color });
final IconThemeColor color;
bool operator ==(dynamic other) {
if (other is! IconThemeData)
return false;
final IconThemeData typedOther = other;
return color == typedOther.color;
}
int get hashCode => color.hashCode;
String toString() => '$color';
}
......@@ -4,7 +4,6 @@
import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
......@@ -29,7 +28,7 @@ class _InkSplash {
_InkSplash(this.position, this.well) {
_targetRadius = _getSplashTargetSize(well.size, position);
_radius = new AnimatedValue<double>(
_kSplashInitialSize, end: _targetRadius, curve: easeOut);
_kSplashInitialSize, end: _targetRadius, curve: Curves.easeOut);
_performance = new ValuePerformance<double>(
variable: _radius,
......@@ -91,7 +90,7 @@ class _InkSplash {
void paint(PaintingCanvas canvas) {
int opacity = (_kSplashInitialOpacity * (1.1 - (_radius.value / _targetRadius))).floor();
ui.Paint paint = new ui.Paint()..color = new ui.Color(opacity << 24);
Paint paint = new Paint()..color = new Color(opacity << 24);
double radius = _pinnedRadius == null ? _radius.value : _pinnedRadius;
canvas.drawCircle(position, radius, paint);
}
......
......@@ -4,8 +4,6 @@
import 'package:flutter/animation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'theme.dart';
......@@ -118,7 +116,7 @@ class _InputState extends ScrollableState<Input> {
return new Listener(
child: new SizeObserver(
callback: _handleContainerSizeChanged,
onSizeChanged: _handleContainerSizeChanged,
child: new Container(
child: new Stack(textChildren),
padding: _kTextfieldPadding,
......
......@@ -2,12 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/widgets.dart';
import 'ink_well.dart';
import 'constants.dart';
class ListItem extends StatelessComponent {
ListItem({
......@@ -44,14 +41,12 @@ class ListItem extends StatelessComponent {
if (right != null) {
children.add(new Container(
margin: new EdgeDims.only(left: 8.0),
width: 40.0,
margin: new EdgeDims.only(left: 16.0),
child: right
));
}
return new Container(
height: kListItemHeight,
return new Padding(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: new InkWell(
onTap: onTap,
......
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/animation.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
......@@ -68,7 +67,7 @@ class Material extends StatelessComponent {
return new DefaultTextStyle(
style: Theme.of(context).text.body1,
child: new AnimatedContainer(
curve: ease,
curve: Curves.ease,
duration: kThemeChangeDuration,
decoration: new BoxDecoration(
backgroundColor: _getBackgroundColor(context),
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
......@@ -28,9 +26,7 @@ class MaterialApp extends StatefulComponent {
this.theme,
this.routes,
this.onGenerateRoute
}) : super(key: key) {
assert(routes != null);
}
}) : super(key: key);
final String title;
final ThemeData theme;
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -48,6 +47,12 @@ abstract class MaterialButton extends StatefulComponent {
final bool enabled;
final ButtonColor textColor;
final GestureTapCallback onPressed;
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (!enabled)
description.add('disabled');
}
}
abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
......
// 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 'constants.dart';
import 'scrollbar_painter.dart';
enum MaterialListType {
oneLine,
oneLineWithAvatar,
twoLine,
threeLine
}
Map<MaterialListType, double> _kItemExtent = const <MaterialListType, double>{
MaterialListType.oneLine: kOneLineListItemHeight,
MaterialListType.oneLineWithAvatar: kOneLineListItemWithAvatarHeight,
MaterialListType.twoLine: kTwoLineListItemHeight,
MaterialListType.threeLine: kThreeLineListItemHeight,
};
class MaterialList<T> extends StatefulComponent {
MaterialList({
Key key,
this.initialScrollOffset,
this.onScroll,
this.items,
this.itemBuilder,
this.type: MaterialListType.twoLine
}) : super(key: key);
final double initialScrollOffset;
final ScrollListener onScroll;
final List<T> items;
final ItemBuilder<T> itemBuilder;
final MaterialListType type;
_MaterialListState<T> createState() => new _MaterialListState<T>();
}
class _MaterialListState<T> extends State<MaterialList<T>> {
void initState() {
super.initState();
_scrollbarPainter = new ScrollbarPainter();
}
ScrollbarPainter _scrollbarPainter;
Widget build(BuildContext context) {
return new ScrollableList<T>(
initialScrollOffset: config.initialScrollOffset,
scrollDirection: ScrollDirection.vertical,
onScroll: config.onScroll,
items: config.items,
itemBuilder: config.itemBuilder,
itemExtent: _kItemExtent[config.type],
padding: const EdgeDims.symmetric(vertical: 8.0),
scrollableListPainter: _scrollbarPainter
);
}
}
......@@ -22,14 +22,11 @@ const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
const double _kMenuHorizontalPadding = 16.0;
const double _kMenuVerticalPadding = 8.0;
typedef List<PopupMenuItem> PopupMenuItemsBuilder(NavigatorState navigator);
class PopupMenu extends StatelessComponent {
PopupMenu({
Key key,
this.items,
this.level: 4,
this.navigator,
this.performance
}) : super(key: key) {
assert(items != null);
......@@ -38,7 +35,6 @@ class PopupMenu extends StatelessComponent {
final List<PopupMenuItem> items;
final int level;
final NavigatorState navigator;
final PerformanceView performance;
Widget build(BuildContext context) {
......@@ -58,7 +54,7 @@ class PopupMenu extends StatelessComponent {
performance: performance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(start, end)),
child: new InkWell(
onTap: () { navigator.pop(items[i].value); },
onTap: () { Navigator.of(context).pop(items[i].value); },
child: items[i]
))
);
......@@ -75,7 +71,7 @@ class PopupMenu extends StatelessComponent {
variables: <AnimatedValue<double>>[width, height],
builder: (BuildContext context) {
return new CustomPaint(
callback: (ui.Canvas canvas, Size size) {
onPaint: (ui.Canvas canvas, Size size) {
double widthValue = width.value * size.width;
double heightValue = height.value * size.height;
painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue));
......@@ -114,11 +110,11 @@ class MenuPosition {
}
class _MenuRoute extends PerformanceRoute {
_MenuRoute({ this.completer, this.position, this.builder, this.level });
_MenuRoute({ this.completer, this.position, this.items, this.level });
final Completer completer;
final MenuPosition position;
final PopupMenuItemsBuilder builder;
final List<PopupMenuItem> items;
final int level;
Performance createPerformance() {
......@@ -134,7 +130,7 @@ class _MenuRoute extends PerformanceRoute {
bool get opaque => false;
Duration get transitionDuration => _kMenuDuration;
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
Widget build(RouteArguments args) {
return new Positioned(
top: position?.top,
right: position?.right,
......@@ -144,9 +140,8 @@ class _MenuRoute extends PerformanceRoute {
key: new GlobalObjectKey(this),
autofocus: true,
child: new PopupMenu(
items: builder != null ? builder(navigator) : const <PopupMenuItem>[],
items: items,
level: level,
navigator: navigator,
performance: performance
)
)
......@@ -159,12 +154,12 @@ class _MenuRoute extends PerformanceRoute {
}
}
Future showMenu({ NavigatorState navigator, MenuPosition position, PopupMenuItemsBuilder builder, int level: 4 }) {
Future showMenu({ BuildContext context, MenuPosition position, List<PopupMenuItem> items, int level: 4 }) {
Completer completer = new Completer();
navigator.push(new _MenuRoute(
Navigator.of(context).push(new _MenuRoute(
completer: completer,
position: position,
builder: builder,
items: items,
level: level
));
return completer.future;
......
......@@ -14,15 +14,15 @@ const double _kLinearProgressIndicatorHeight = 6.0;
const double _kMinCircularProgressIndicatorSize = 15.0;
const double _kCircularProgressIndicatorStrokeWidth = 3.0;
// TODO(hansmuller) implement the support for buffer indicator
abstract class ProgressIndicator extends StatefulComponent {
ProgressIndicator({
Key key,
this.value,
this.bufferValue
this.value
}) : super(key: key);
final double value; // Null for non-determinate progress indicator.
final double bufferValue; // TODO(hansmuller) implement the support for this.
Color _getBackgroundColor(BuildContext context) => Theme.of(context).primarySwatch[200];
Color _getValueColor(BuildContext context) => Theme.of(context).primaryColor;
......@@ -31,6 +31,11 @@ abstract class ProgressIndicator extends StatefulComponent {
Widget _buildIndicator(BuildContext context, double performanceValue);
_ProgressIndicatorState createState() => new _ProgressIndicatorState();
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('${(value.clamp(0.0, 1.0) * 100.0).toStringAsFixed(1)}%');
}
}
class _ProgressIndicatorState extends State<ProgressIndicator> {
......@@ -40,7 +45,7 @@ class _ProgressIndicatorState extends State<ProgressIndicator> {
void initState() {
super.initState();
_performance = new ValuePerformance<double>(
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: ease),
variable: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease),
duration: const Duration(milliseconds: 1500)
);
_performance.addStatusListener((PerformanceStatus status) {
......@@ -72,14 +77,13 @@ class _ProgressIndicatorState extends State<ProgressIndicator> {
class LinearProgressIndicator extends ProgressIndicator {
LinearProgressIndicator({
Key key,
double value,
double bufferValue
}) : super(key: key, value: value, bufferValue: bufferValue);
double value
}) : super(key: key, value: value);
void _paint(BuildContext context, double performanceValue, ui.Canvas canvas, Size size) {
void _paint(BuildContext context, double performanceValue, Canvas canvas, Size size) {
Paint paint = new Paint()
..color = _getBackgroundColor(context)
..setStyle(ui.PaintingStyle.fill);
..style = ui.PaintingStyle.fill;
canvas.drawRect(Point.origin & size, paint);
paint.color = _getValueColor(context);
......@@ -103,7 +107,7 @@ class LinearProgressIndicator extends ProgressIndicator {
),
child: new CustomPaint(
token: _getCustomPaintToken(performanceValue),
callback: (ui.Canvas canvas, Size size) {
onPaint: (Canvas canvas, Size size) {
_paint(context, performanceValue, canvas, size);
}
)
......@@ -120,19 +124,18 @@ class CircularProgressIndicator extends ProgressIndicator {
CircularProgressIndicator({
Key key,
double value,
double bufferValue
}) : super(key: key, value: value, bufferValue: bufferValue);
double value
}) : super(key: key, value: value);
void _paint(BuildContext context, double performanceValue, ui.Canvas canvas, Size size) {
void _paint(BuildContext context, double performanceValue, Canvas canvas, Size size) {
Paint paint = new Paint()
..color = _getValueColor(context)
..strokeWidth = _kCircularProgressIndicatorStrokeWidth
..setStyle(ui.PaintingStyle.stroke);
..style = ui.PaintingStyle.stroke;
if (value != null) {
double angle = value.clamp(0.0, 1.0) * _kSweep;
ui.Path path = new ui.Path()
Path path = new Path()
..arcTo(Point.origin & size, _kStartAngle, angle, false);
canvas.drawPath(path, paint);
} else {
......@@ -140,7 +143,7 @@ class CircularProgressIndicator extends ProgressIndicator {
double endAngle = startAngle + _kTwoPI * 0.75;
double arcAngle = startAngle.clamp(0.0, _kTwoPI);
double arcSweep = endAngle.clamp(0.0, _kTwoPI) - arcAngle;
ui.Path path = new ui.Path()
Path path = new Path()
..arcTo(Point.origin & size, _kStartAngle + arcAngle, arcSweep, false);
canvas.drawPath(path, paint);
}
......@@ -154,7 +157,7 @@ class CircularProgressIndicator extends ProgressIndicator {
),
child: new CustomPaint(
token: _getCustomPaintToken(performanceValue),
callback: (ui.Canvas canvas, Size size) {
onPaint: (Canvas canvas, Size size) {
_paint(context, performanceValue, canvas, size);
}
)
......
......@@ -3,10 +3,9 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset, Color, Paint;
import 'package:flutter/animation.dart';
import 'package:flutter/painting.dart';
const Duration _kShowDuration = const Duration(milliseconds: 300);
const Duration _kHideDuration = const Duration(milliseconds: 200);
......@@ -27,9 +26,9 @@ class RadialReaction {
this.radius,
Point startPosition
}) {
_outerOpacity = new AnimatedValue<double>(0.0, end: _kMaxOpacity, curve: easeOut);
_innerCenter = new AnimatedValue<Point>(startPosition, end: center, curve: easeOut);
_innerRadius = new AnimatedValue<double>(0.0, end: radius, curve: easeOut);
_outerOpacity = new AnimatedValue<double>(0.0, end: _kMaxOpacity, curve: Curves.easeOut);
_innerCenter = new AnimatedValue<Point>(startPosition, end: center, curve: Curves.easeOut);
_innerRadius = new AnimatedValue<double>(0.0, end: radius, curve: Curves.easeOut);
_showPerformance = new Performance(duration: _kShowDuration)
..addListener(() {
_showPerformance.updateVariable(_outerOpacity);
......@@ -37,7 +36,7 @@ class RadialReaction {
_showPerformance.updateVariable(_innerRadius);
});
_fade = new ValuePerformance<double>(
variable: new AnimatedValue<double>(1.0, end: 0.0, curve: easeIn),
variable: new AnimatedValue<double>(1.0, end: 0.0, curve: Curves.easeIn),
duration: _kHideDuration
);
}
......@@ -82,7 +81,7 @@ class RadialReaction {
final Paint _innerPaint = new Paint();
/// Paint the reaction onto the given canvas at the given offset
void paint(ui.Canvas canvas, Offset offset) {
void paint(Canvas canvas, Offset offset) {
_outerPaint.color = _kOuterColor.withAlpha(_roundOpacity(_outerOpacity.value * _fade.value));
canvas.drawCircle(center + offset, radius, _outerPaint);
......
......@@ -8,8 +8,8 @@ import 'package:flutter/widgets.dart';
import 'theme.dart';
const ui.Color _kLightOffColor = const ui.Color(0x8A000000);
const ui.Color _kDarkOffColor = const ui.Color(0xB2FFFFFF);
const Color _kLightOffColor = const Color(0x8A000000);
const Color _kDarkOffColor = const Color(0xB2FFFFFF);
typedef void RadioValueChanged(Object value);
......@@ -45,18 +45,18 @@ class Radio extends StatelessComponent {
width: kDiameter,
height: kDiameter,
child: new CustomPaint(
callback: (ui.Canvas canvas, Size size) {
Paint paint = new Paint()..color = _getColor(context);
onPaint: (Canvas canvas, Size size) {
// Draw the outer circle
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 2.0;
Paint paint = new Paint()
..color = _getColor(context)
..style = ui.PaintingStyle.stroke
..strokeWidth = 2.0;
canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kOuterRadius, paint);
// Draw the inner circle
if (value == groupValue) {
paint.setStyle(ui.PaintingStyle.fill);
paint.style = ui.PaintingStyle.fill;
canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kInnerRadius, paint);
}
}
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......
......@@ -4,10 +4,10 @@
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'material.dart';
class Scaffold extends StatelessComponent {
Scaffold({
......@@ -39,7 +39,9 @@ class Scaffold extends StatelessComponent {
if (body != null) {
children.add(new Positioned(
top: toolBarHeight, right: 0.0, bottom: statusBarHeight, left: 0.0,
child: body
child: new Material(
child: body
)
));
}
......
......@@ -62,7 +62,7 @@ class ScrollbarPainter extends ScrollableListPainter {
Future scrollStarted() {
_fade ??= new ValuePerformance<double>()
..duration = _kScrollbarThumbFadeDuration
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease)
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.ease)
..addListener(() {
_opacity = _fade.value;
renderer?.markNeedsPaint();
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
......@@ -69,8 +67,8 @@ class SnackBar extends StatelessComponent {
height: new AnimatedValue<double>(
0.0,
end: kSnackBarHeight,
curve: easeIn,
reverseCurve: easeOut
curve: Curves.easeIn,
reverseCurve: Curves.easeOut
),
child: new ClipRect(
child: new OverflowBox(
......@@ -104,10 +102,10 @@ class _SnackBarRoute extends PerformanceRoute {
bool get modal => false;
Duration get transitionDuration => const Duration(milliseconds: 200);
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) => null;
Widget build(RouteArguments args) => null;
}
void showSnackBar({ NavigatorState navigator, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
void showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
Route route = new _SnackBarRoute();
SnackBar snackBar = new SnackBar(
content: content,
......@@ -115,5 +113,5 @@ void showSnackBar({ NavigatorState navigator, GlobalKey<PlaceholderState> placeh
performance: route.performance
);
placeholderKey.currentState.child = snackBar;
navigator.push(route);
Navigator.of(context).push(route);
}
......@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/painting.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
......@@ -16,8 +15,8 @@ import 'theme.dart';
export 'package:flutter/rendering.dart' show ValueChanged;
const ui.Color _kThumbOffColor = const ui.Color(0xFFFAFAFA);
const ui.Color _kTrackOffColor = const ui.Color(0x42000000);
const Color _kThumbOffColor = const Color(0xFFFAFAFA);
const Color _kTrackOffColor = const Color(0x42000000);
const double _kSwitchWidth = 35.0;
const double _kThumbRadius = 10.0;
const double _kSwitchHeight = _kThumbRadius * 2.0;
......@@ -113,18 +112,18 @@ class _RenderSwitch extends RenderToggleable {
void paint(PaintingContext context, Offset offset) {
final PaintingCanvas canvas = context.canvas;
ui.Color thumbColor = _kThumbOffColor;
ui.Color trackColor = _kTrackOffColor;
Color thumbColor = _kThumbOffColor;
Color trackColor = _kTrackOffColor;
if (value) {
thumbColor = _thumbColor;
trackColor = new ui.Color(_thumbColor.value & 0x80FFFFFF);
trackColor = new Color(_thumbColor.value & 0x80FFFFFF);
}
// Draw the track rrect
ui.Paint paint = new ui.Paint()
Paint paint = new Paint()
..color = trackColor
..style = ui.PaintingStyle.fill;
ui.Rect rect = new ui.Rect.fromLTWH(offset.dx,
Rect rect = new Rect.fromLTWH(offset.dx,
offset.dy + _kSwitchHeight / 2.0 - _kTrackHeight / 2.0, _kTrackWidth,
_kTrackHeight);
ui.RRect rrect = new ui.RRect()
......
......@@ -3,21 +3,19 @@
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:newton/newton.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
import 'constants.dart';
import 'icon.dart';
import 'icon_theme.dart';
import 'icon_theme_data.dart';
import 'ink_well.dart';
import 'theme.dart';
import 'typography.dart';
typedef void TabSelectedIndexChanged(int selectedIndex);
typedef void TabLayoutChanged(Size size, List<double> widths);
......@@ -283,6 +281,16 @@ class TabLabel {
final String text;
final String icon;
String toString() {
if (text != null && icon != null)
return '"$text" ($icon)';
if (text != null)
return '"$text"';
if (icon != null)
return '$icon';
return 'EMPTY TAB LABEL';
}
}
class Tab extends StatelessComponent {
......@@ -312,7 +320,7 @@ class Tab extends StatelessComponent {
Widget _buildLabelIcon() {
assert(label.icon != null);
Color iconColor = selected ? selectedColor : color;
ui.ColorFilter filter = new ui.ColorFilter.mode(iconColor, ui.TransferMode.srcATop);
ColorFilter filter = new ColorFilter.mode(iconColor, TransferMode.srcATop);
return new Icon(type: label.icon, size: _kTabIconSize, colorFilter: filter);
}
......@@ -337,7 +345,7 @@ class Tab extends StatelessComponent {
}
Container centeredLabel = new Container(
child: new Center(child: labelContent),
child: new Center(child: labelContent, shrinkWrap: ShrinkWrap.both),
constraints: new BoxConstraints(minWidth: _kMinTabWidth),
padding: _kTabLabelPadding
);
......@@ -347,6 +355,11 @@ class Tab extends StatelessComponent {
child: centeredLabel
);
}
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$label');
}
}
class _TabsScrollBehavior extends BoundedBehavior {
......@@ -391,7 +404,7 @@ class _TabBarState extends ScrollableState<TabBar> {
super.initState();
_indicatorAnimation = new ValuePerformance<Rect>()
..duration = _kTabBarScroll
..variable = new AnimatedRectValue(null, curve: ease);
..variable = new AnimatedRectValue(null, curve: Curves.ease);
scrollBehavior.isScrollable = config.isScrollable;
}
......@@ -496,18 +509,8 @@ class _TabBarState extends ScrollableState<TabBar> {
indicatorColor = Colors.white;
}
TextStyle textStyle;
IconThemeColor iconThemeColor;
switch (themeData.primaryColorBrightness) {
case ThemeBrightness.light:
textStyle = Typography.black.body1;
iconThemeColor = IconThemeColor.black;
break;
case ThemeBrightness.dark:
textStyle = Typography.white.body1;
iconThemeColor = IconThemeColor.white;
break;
}
TextStyle textStyle = themeData.primaryTextTheme.body1;
IconThemeData iconTheme = themeData.primaryIconTheme;
List<Widget> tabs = <Widget>[];
bool textAndIcons = false;
......@@ -519,7 +522,7 @@ class _TabBarState extends ScrollableState<TabBar> {
}
Widget content = new IconTheme(
data: new IconThemeData(color: iconThemeColor),
data: iconTheme,
child: new DefaultTextStyle(
style: textStyle,
child: new BuilderTransition(
......@@ -542,7 +545,7 @@ class _TabBarState extends ScrollableState<TabBar> {
if (config.isScrollable) {
content = new SizeObserver(
callback: _handleViewportSizeChanged,
onSizeChanged: _handleViewportSizeChanged,
child: new Viewport(
scrollDirection: ScrollDirection.horizontal,
scrollOffset: new Offset(scrollOffset, 0.0),
......
......@@ -28,4 +28,9 @@ class Theme extends InheritedWidget {
}
bool updateShouldNotify(Theme old) => data != old.data;
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$data');
}
}
......@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui';
import 'dart:ui' show Color;
import 'package:flutter/src/material/typography.dart';
import 'package:flutter/src/material/colors.dart';
import 'colors.dart';
import 'icon_theme_data.dart';
import 'typography.dart';
enum ThemeBrightness { dark, light }
......@@ -82,6 +83,19 @@ class ThemeData {
/// icons placed on top of the primary color (e.g. toolbar text).
final ThemeBrightness primaryColorBrightness;
/// A text theme that contrasts with the primary color.
TextTheme get primaryTextTheme {
if (primaryColorBrightness == ThemeBrightness.dark)
return Typography.white;
return Typography.black;
}
IconThemeData get primaryIconTheme {
if (primaryColorBrightness == ThemeBrightness.dark)
return const IconThemeData(color: IconThemeColor.white);
return const IconThemeData(color: IconThemeColor.black);
}
/// The foreground color for widgets (knobs, text, etc)
Color get accentColor => _accentColor;
Color _accentColor;
......@@ -124,4 +138,6 @@ class ThemeData {
value = 37 * value + accentColorBrightness.hashCode;
return value;
}
String toString() => '$primaryColor $brightness etc...';
}
......@@ -17,4 +17,9 @@ class Title extends StatelessComponent {
updateTaskDescription(title, Theme.of(context).primaryColor);
return child;
}
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('"$title"');
}
}
......@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/painting.dart';
import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'icon.dart';
import 'icon_theme.dart';
import 'icon_theme_data.dart';
import 'shadows.dart';
import 'theme.dart';
import 'typography.dart';
......@@ -18,7 +18,8 @@ class ToolBar extends StatelessComponent {
this.center,
this.right,
this.level: 2,
this.backgroundColor
this.backgroundColor,
this.textTheme
}) : super(key: key);
final Widget left;
......@@ -26,22 +27,22 @@ class ToolBar extends StatelessComponent {
final List<Widget> right;
final int level;
final Color backgroundColor;
final TextTheme textTheme;
Widget build(BuildContext context) {
Color color = backgroundColor;
IconThemeData iconThemeData;
TextStyle centerStyle = Typography.white.title;
TextStyle sideStyle = Typography.white.body1;
if (color == null) {
TextStyle centerStyle = textTheme?.title;
TextStyle sideStyle = textTheme?.body1;
if (color == null || iconThemeData == null || textTheme == null) {
ThemeData themeData = Theme.of(context);
color = themeData.primaryColor;
if (themeData.primaryColorBrightness == ThemeBrightness.light) {
centerStyle = Typography.black.title;
sideStyle = Typography.black.body2;
iconThemeData = const IconThemeData(color: IconThemeColor.black);
} else {
iconThemeData = const IconThemeData(color: IconThemeColor.white);
}
color ??= themeData.primaryColor;
iconThemeData ??= themeData.primaryIconTheme;
TextTheme primaryTextTheme = themeData.primaryTextTheme;
centerStyle ??= primaryTextTheme.title;
sideStyle ??= primaryTextTheme.body2;
}
List<Widget> children = new List<Widget>();
......
......@@ -7,7 +7,8 @@
import 'dart:ui' show Color;
import 'package:flutter/painting.dart';
import 'package:flutter/src/material/colors.dart';
import 'colors.dart';
// TODO(eseidel): Font weights are supposed to be language relative!
// TODO(jackson): Baseline should be language relative!
......
// 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.
export 'dart:ui' show
Canvas,
Color,
ColorFilter,
FontStyle,
FontWeight,
Offset,
Paint,
Path,
Point,
Rect,
Size,
TextAlign,
TextBaseline,
TextDecoration,
TextDecorationStyle;
......@@ -4,10 +4,9 @@
import 'dart:ui' as ui;
import 'basic_types.dart';
import 'text_style.dart';
export 'text_style.dart';
/// An immutable span of text
abstract class TextSpan {
// This class must be immutable, because we won't notice when it changes
......
......@@ -3,9 +3,8 @@
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path, FontWeight, FontStyle, TextAlign, TextBaseline, TextDecoration, TextDecorationStyle;
export 'dart:ui' show FontWeight, FontStyle, TextAlign, TextBaseline, TextDecoration, TextDecorationStyle;
import 'basic_types.dart';
/// A normal font weight
const normal = FontWeight.w400;
......
// 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.
export 'dart:ui' show
Canvas,
Color,
ColorFilter,
Offset,
Paint,
Path,
Point,
Rect,
Size,
TransferMode;
......@@ -6,6 +6,7 @@ import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'box.dart';
import 'hit_test.dart';
......@@ -61,7 +62,8 @@ class _UiEventConverter {
Point position = new Point(event.x, event.y);
_PointerState state = _stateForPointer[event.pointer];
double dx, dy;
double dx = 0.0;
double dy = 0.0;
switch (event.type) {
case 'pointerdown':
if (state == null) {
......@@ -252,5 +254,5 @@ class FlutterBinding extends HitTestTarget {
/// Prints a textual representation of the entire render tree
void debugDumpRenderTree() {
FlutterBinding.instance.renderView.toStringDeep().split('\n').forEach(print);
debugPrint(FlutterBinding.instance.renderView.toStringDeep());
}
......@@ -254,7 +254,21 @@ class BoxConstraints extends Constraints {
return value;
}
String toString() => "BoxConstraints($minWidth<=w<=$maxWidth, $minHeight<=h<=$maxHeight)";
String toString() {
if (minWidth == double.INFINITY && minHeight == double.INFINITY)
return 'BoxConstraints(biggest)';
if (minWidth == 0 && maxWidth == double.INFINITY &&
minHeight == 0 && maxHeight == double.INFINITY)
return 'BoxConstraints(unconstrained)';
String describe(double min, double max, String dim) {
if (min == max)
return '$dim=${min.toStringAsFixed(1)}';
return '${min.toStringAsFixed(1)}<=$dim<=${max.toStringAsFixed(1)}';
}
final String width = describe(minWidth, maxWidth, 'w');
final String height = describe(minHeight, maxHeight, 'h');
return 'BoxConstraints($width, $height)';
}
}
/// A hit test entry used by [RenderBox]
......@@ -359,9 +373,11 @@ abstract class RenderBox extends RenderObject {
final _DebugSize _size = this._size;
assert(_size._owner == this);
if (RenderObject.debugActiveLayout != null) {
// we are always allowed to access our own size (for print debugging and asserts if nothing else)
// other than us, the only object that's allowed to read our size is our parent, if they're said they will
// if you hit this assert trying to access a child's size, pass parentUsesSize: true in layout()
// We are always allowed to access our own size (for print debugging
// and asserts if nothing else). Other than us, the only object that's
// allowed to read our size is our parent, if they've said they will.
// If you hit this assert trying to access a child's size, pass
// "parentUsesSize: true" to that child's layout().
assert(debugDoingThisResize || debugDoingThisLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent));
}
......@@ -377,8 +393,12 @@ abstract class RenderBox extends RenderObject {
assert((sizedByParent && debugDoingThisResize) ||
(!sizedByParent && debugDoingThisLayout));
assert(() {
if (value is _DebugSize)
return value._canBeUsedByParent && value._owner.parent == this;
if (value is _DebugSize) {
if (value._owner != this) {
assert(value._owner.parent == this);
assert(value._canBeUsedByParent);
}
}
return true;
});
_size = value;
......@@ -389,6 +409,11 @@ abstract class RenderBox extends RenderObject {
assert(debugDoesMeetConstraints());
}
void debugResetSize() {
// updates the value of size._canBeUsedByParent if necessary
size = size;
}
Map<TextBaseline, double> _cachedBaselines;
bool _ancestorUsesBaseline = false;
static bool _debugDoingBaseline = false;
......@@ -473,7 +498,7 @@ abstract class RenderBox extends RenderObject {
});
bool result = constraints.isSatisfiedBy(_size);
if (!result)
print("${this.runtimeType} does not meet its constraints. Constraints: $constraints, size: $_size");
debugPrint("${this.runtimeType} does not meet its constraints. Constraints: $constraints, size: $_size");
return result;
}
......@@ -602,16 +627,16 @@ abstract class RenderBox extends RenderObject {
debugPaintBaselines(context, offset);
}
void debugPaintSize(PaintingContext context, Offset offset) {
Paint paint = new Paint();
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 1.0;
paint.color = debugPaintSizeColor;
Paint paint = new Paint()
..style = ui.PaintingStyle.stroke
..strokeWidth = 1.0
..color = debugPaintSizeColor;
context.canvas.drawRect(offset & size, paint);
}
void debugPaintBaselines(PaintingContext context, Offset offset) {
Paint paint = new Paint();
paint.setStyle(ui.PaintingStyle.stroke);
paint.strokeWidth = 0.25;
Paint paint = new Paint()
..style = ui.PaintingStyle.stroke
..strokeWidth = 0.25;
Path path;
// ideographic baseline
double baselineI = getDistanceToBaseline(TextBaseline.ideographic, onlyReal: true);
......@@ -712,3 +737,27 @@ abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare
}
}
}
/// An offset that's expressed as a fraction of a Size.
///
/// FractionalOffset(1.0, 0.0) represents the top right of the Size,
/// FractionalOffset(0.0, 1.0) represents the bottom left of the Size,
class FractionalOffset {
const FractionalOffset(this.x, this.y);
final double x;
final double y;
bool operator ==(dynamic other) {
if (other is! FractionalOffset)
return false;
final FractionalOffset typedOther = other;
return x == typedOther.x &&
y == typedOther.y;
}
int get hashCode {
int value = 373;
value = 37 * value + x.hashCode;
value = 37 * value + y.hashCode;
return value;
}
String toString() => '$runtimeType($x, $y)';
}
......@@ -3,6 +3,8 @@
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'dart:async';
import 'dart:collection';
/// Causes each RenderBox to paint a box around its bounds.
bool debugPaintSizeEnabled = false;
......@@ -30,3 +32,43 @@ bool debugPaintBoundsEnabled = false;
/// The color to use when painting RenderError boxes in checked mode.
ui.Color debugErrorBoxColor = const ui.Color(0xFFFF0000);
/// Prints a message to the console, which you can access using the "flutter"
/// tool's "logs" command ("flutter logs").
///
/// This function very crudely attempts to throttle the rate at which messages
/// are sent to avoid data loss on Android. This means that interleaving calls
/// to this function (directly or indirectly via [debugDumpRenderTree] or
/// [debugDumpApp]) and to the Dart [print] method can result in out-of-order
/// messages in the logs.
void debugPrint(String message) {
_debugPrintBuffer.addAll(message.split('\n'));
if (!_debugPrintScheduled)
_debugPrintTask();
}
int _debugPrintedCharacters = 0;
int _kDebugPrintCapacity = 16 * 1024;
Duration _kDebugPrintPauseTime = const Duration(seconds: 1);
Queue<String> _debugPrintBuffer = new Queue<String>();
Stopwatch _debugPrintStopwatch = new Stopwatch();
bool _debugPrintScheduled = false;
void _debugPrintTask() {
_debugPrintScheduled = false;
if (_debugPrintStopwatch.elapsed > _kDebugPrintPauseTime) {
_debugPrintStopwatch.stop();
_debugPrintStopwatch.reset();
_debugPrintedCharacters = 0;
}
while (_debugPrintedCharacters < _kDebugPrintCapacity && _debugPrintBuffer.length > 0) {
String line = _debugPrintBuffer.removeFirst();
_debugPrintedCharacters += line.length; // TODO(ianh): Use the UTF-8 byte length instead
print(line);
}
if (_debugPrintBuffer.length > 0) {
_debugPrintScheduled = true;
_debugPrintedCharacters = 0;
new Timer(_kDebugPrintPauseTime, _debugPrintTask);
} else {
_debugPrintStopwatch.start();
}
}
......@@ -9,6 +9,10 @@ import 'package:flutter/painting.dart';
import 'box.dart';
import 'object.dart';
export 'package:flutter/painting.dart' show
ImageFit,
ImageRepeat;
/// An image in the render tree.
///
/// The render image attempts to find a size for itself that fits in the given
......@@ -18,7 +22,7 @@ class RenderImage extends RenderBox {
ui.Image image,
double width,
double height,
ui.ColorFilter colorFilter,
ColorFilter colorFilter,
ImageFit fit,
repeat: ImageRepeat.noRepeat,
Rect centerSlice
......@@ -63,9 +67,9 @@ class RenderImage extends RenderBox {
}
/// If non-null, apply this color filter to the image before painint.
ui.ColorFilter get colorFilter => _colorFilter;
ui.ColorFilter _colorFilter;
void set colorFilter (ui.ColorFilter value) {
ColorFilter get colorFilter => _colorFilter;
ColorFilter _colorFilter;
void set colorFilter (ColorFilter value) {
if (value == _colorFilter)
return;
_colorFilter = value;
......
......@@ -3,10 +3,13 @@
// found in the LICENSE file.
import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path;
import 'package:vector_math/vector_math_64.dart';
import 'basic_types.dart';
export 'basic_types.dart';
/// A composited layer
///
/// During painting, the render tree generates a tree of composited layers that
......@@ -304,29 +307,3 @@ class OpacityLayer extends ContainerLayer {
builder.pop();
}
}
/// A composited layer that applies a color filter to its children
class ColorFilterLayer extends ContainerLayer {
ColorFilterLayer({
Offset offset: Offset.zero,
this.bounds,
this.color,
this.transferMode
}) : super(offset: offset);
/// Unused
Rect bounds;
// TODO(abarth): Remove.
/// The color to use as input to the color filter
Color color;
/// The transfer mode to use to combine [color] with the children's painting
ui.TransferMode transferMode;
void addToScene(ui.SceneBuilder builder, Offset layerOffset) {
builder.pushColorFilter(color, transferMode, bounds.shift(offset));
addChildrenToScene(builder, offset + layerOffset);
builder.pop();
}
}
......@@ -4,7 +4,6 @@
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path;
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
......@@ -15,8 +14,8 @@ import 'hit_test.dart';
import 'layer.dart';
import 'node.dart';
export 'dart:ui' show Point, Offset, Size, Rect, Color, Paint, Path;
export 'hit_test.dart' show HitTestTarget, HitTestEntry, HitTestResult;
export 'layer.dart';
export 'hit_test.dart';
typedef ui.Shader ShaderCallback(Rect bounds);
......@@ -39,7 +38,7 @@ class ParentData {
}
/// Obsolete class that will be removed eventually
class PaintingCanvas extends ui.Canvas {
class PaintingCanvas extends Canvas {
PaintingCanvas(ui.PictureRecorder recorder, Rect bounds) : super(recorder, bounds);
// TODO(ianh): Just use ui.Canvas everywhere instead
}
......@@ -247,7 +246,7 @@ class PaintingContext {
static Paint _getPaintForAlpha(int alpha) {
return new Paint()
..color = new Color.fromARGB(alpha, 0, 0, 0)
..setTransferMode(ui.TransferMode.srcOver)
..transferMode = TransferMode.srcOver
..isAntiAlias = false;
}
......@@ -277,46 +276,9 @@ class PaintingContext {
}
}
static Paint _getPaintForColorFilter(Color color, ui.TransferMode transferMode) {
return new Paint()
..colorFilter = new ui.ColorFilter.mode(color, transferMode)
..isAntiAlias = false;
}
/// Paint a child with a color filter
///
/// The color filter is constructed by combining the given color and the given
/// transfer mode, as if they were passed to the [ColorFilter.mode] constructor.
///
/// If the child needs compositing, the blending operation will be applied by
/// a compositing layer. Otherwise, the blending operation will be applied by
/// the canvas.
void paintChildWithColorFilter(RenderObject child,
Point childPosition,
Rect bounds,
Color color,
ui.TransferMode transferMode) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
canvas.saveLayer(bounds, _getPaintForColorFilter(color, transferMode));
canvas.translate(childOffset.dx, childOffset.dy);
insertChild(child, Offset.zero);
canvas.restore();
} else {
ColorFilterLayer paintLayer = new ColorFilterLayer(
offset: childOffset,
bounds: bounds,
color: color,
transferMode: transferMode);
_containerLayer.append(paintLayer);
compositeChild(child, parentLayer: paintLayer);
}
}
static Paint _getPaintForShaderMask(Rect bounds,
ShaderCallback shaderCallback,
ui.TransferMode transferMode) {
TransferMode transferMode) {
return new Paint()
..transferMode = transferMode
..shader = shaderCallback(bounds);
......@@ -326,7 +288,7 @@ class PaintingContext {
Point childPosition,
Rect bounds,
ShaderCallback shaderCallback,
ui.TransferMode transferMode) {
TransferMode transferMode) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
......@@ -514,14 +476,14 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
dynamic debugExceptionContext = '';
void _debugReportException(String method, dynamic exception, StackTrace stack) {
print('-- EXCEPTION --');
print('The following exception was raised during $method():');
print('$exception');
print('Stack trace:');
print('$stack');
print('The following RenderObject was being processed when the exception was fired:\n${this}');
debugPrint('-- EXCEPTION --');
debugPrint('The following exception was raised during $method():');
debugPrint('$exception');
debugPrint('Stack trace:');
debugPrint('$stack');
debugPrint('The following RenderObject was being processed when the exception was fired:\n${this}');
if (debugExceptionContext != '')
'That RenderObject had the following exception context:\n$debugExceptionContext'.split('\n').forEach(print);
debugPrint('That RenderObject had the following exception context:\n$debugExceptionContext');
if (debugRenderingExceptionHandler != null)
debugRenderingExceptionHandler(this, method, exception, stack);
}
......@@ -724,15 +686,30 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
else
relayoutSubtreeRoot = parent._relayoutSubtreeRoot;
assert(parent == this.parent);
if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _relayoutSubtreeRoot)
assert(() {
_debugCanParentUseSize = parentUsesSize;
return true;
});
if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _relayoutSubtreeRoot) {
assert(() {
// in case parentUsesSize changed since the last invocation, set size
// to itself, so it has the right internal debug values.
_debugDoingThisLayout = true;
RenderObject debugPreviousActiveLayout = _debugActiveLayout;
_debugActiveLayout = this;
debugResetSize();
_debugActiveLayout = debugPreviousActiveLayout;
_debugDoingThisLayout = false;
return true;
});
return;
}
_constraints = constraints;
_relayoutSubtreeRoot = relayoutSubtreeRoot;
assert(!_debugMutationsLocked);
assert(!_doingThisLayoutWithCallback);
assert(() {
_debugMutationsLocked = true;
_debugCanParentUseSize = parentUsesSize;
return true;
});
if (sizedByParent) {
......@@ -769,6 +746,14 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(parent == this.parent);
}
/// If a subclass has a "size" (the state controlled by "parentUsesSize",
/// whatever it is in the subclass, e.g. the actual "size" property of
/// RenderBox), and the subclass verifies that in checked mode this "size"
/// property isn't used when debugCanParentUseSize isn't set, then that
/// subclass should override debugResetSize() to reapply the current values of
/// debugCanParentUseSize to that state.
void debugResetSize() { }
/// Whether the constraints are the only input to the sizing algorithm (in
/// particular, child nodes have no impact)
///
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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