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