Commit ad569a23 authored by Collin Jackson's avatar Collin Jackson

Merge remote-tracking branch 'dk/master' into meal

Conflicts:
	sky/sdk/example/fitness/lib/feed.dart
parents 1f768ce2 4dacd69b
...@@ -52,7 +52,6 @@ dart_pkg("sky") { ...@@ -52,7 +52,6 @@ dart_pkg("sky") {
"lib/theme/view_configuration.dart", "lib/theme/view_configuration.dart",
"lib/widgets/animated_component.dart", "lib/widgets/animated_component.dart",
"lib/widgets/animated_container.dart", "lib/widgets/animated_container.dart",
"lib/widgets/animation_builder.dart",
"lib/widgets/basic.dart", "lib/widgets/basic.dart",
"lib/widgets/block_viewport.dart", "lib/widgets/block_viewport.dart",
"lib/widgets/button_base.dart", "lib/widgets/button_base.dart",
......
## 0.0.20
- 167 changes: https://github.com/domokit/mojo/compare/f2830c7...603f589
## 0.0.19 ## 0.0.19
- 49 changes: https://github.com/domokit/mojo/compare/a64559a...1b8968c - 49 changes: https://github.com/domokit/mojo/compare/a64559a...1b8968c
......
...@@ -3,7 +3,9 @@ Getting started with Sky ...@@ -3,7 +3,9 @@ Getting started with Sky
Sky apps are written in Dart. To get started, we need to set up Dart SDK: Sky apps are written in Dart. To get started, we need to set up Dart SDK:
- Install the [Dart SDK](https://www.dartlang.org/downloads/). - Install the [Dart SDK](https://www.dartlang.org/downloads/):
- Mac: `brew tap dart-lang/dart && brew install dart`
- Linux: See [https://www.dartlang.org/downloads/linux.html](https://www.dartlang.org/downloads/linux.html)
- Ensure that `$DART_SDK` is set to the path of your Dart SDK and that the - Ensure that `$DART_SDK` is set to the path of your Dart SDK and that the
`dart` and `pub` executables are on your `$PATH`. `dart` and `pub` executables are on your `$PATH`.
...@@ -44,20 +46,20 @@ The `HelloWorldApp` builds a `Text` widget containing the traditional `Hello, wo ...@@ -44,20 +46,20 @@ The `HelloWorldApp` builds a `Text` widget containing the traditional `Hello, wo
string and centers it on the screen using a `Center` widget. To learn more about string and centers it on the screen using a `Center` widget. To learn more about
the widget system, please see the [widgets tutorial](lib/widgets/README.md). the widget system, please see the [widgets tutorial](lib/widgets/README.md).
Setup your Android device Setting up your Android device
------------------------- -------------------------
Currently Sky requires an Android device running the Lollipop (or newer) version Currently Sky requires an Android device running the Lollipop (or newer) version
of the Android operating system. of the Android operating system.
- Install the `adb` tool from the [Android SDK](https://developer.android.com/sdk/installing/index.html) - Install the `adb` tool from the [Android SDK](https://developer.android.com/sdk/installing/index.html?pkg=tools):
and ensure that `adb` (inside `platform-tools` in the Android SDK) is in your - Mac: `brew install android-platform-tools`
`$PATH`. - Linux: `sudo apt-get install android-tools-adb`
- Enable developer mode on your device by visiting `Settings > About phone` - Enable developer mode on your device by visiting `Settings > About phone`
and tapping the `Build number` field five times. and tapping the `Build number` field five times.
- Enable `USB debugging` in `Settings > Developer options`. - Enable `Android debugging` in `Settings > Developer options`.
- Using a USB cable, plug your phone into your computer. If prompted on your - Using a USB cable, plug your phone into your computer. If prompted on your
device, authorize your computer to access your device. device, authorize your computer to access your device.
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,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.
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.domokit.sky.demo" android:versionCode="19" android:versionName="0.0.19"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.domokit.sky.demo" android:versionCode="20" android:versionName="0.0.20">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
......
...@@ -60,9 +60,9 @@ class SkyDemo { ...@@ -60,9 +60,9 @@ class SkyDemo {
this.description, this.description,
this.textTheme, this.textTheme,
this.decoration this.decoration
}) : name = name, key = name; }) : name = name, key = new Key(name);
final String name; final String name;
final String key; final Key key;
final String href; final String href;
final String bundle; final String bundle;
final String description; final String description;
......
...@@ -28,7 +28,7 @@ import 'measurement.dart'; ...@@ -28,7 +28,7 @@ import 'measurement.dart';
import 'meal.dart'; import 'meal.dart';
class FitnessItemList extends Component { class FitnessItemList extends Component {
FitnessItemList({ String key, this.items, this.onDismissed }) : super(key: key); FitnessItemList({ Key key, this.items, this.onDismissed }) : super(key: key);
final List<FitnessItem> items; final List<FitnessItem> items;
final FitnessItemHandler onDismissed; final FitnessItemHandler onDismissed;
...@@ -50,7 +50,55 @@ class FitnessItemList extends Component { ...@@ -50,7 +50,55 @@ class FitnessItemList extends Component {
class FeedFragment extends StatefulComponent { class FeedFragment extends StatefulComponent {
<<<<<<< HEAD:sky/sdk/example/fitness/lib/feed.dart
FeedFragment({ this.navigator, this.userData, this.onItemCreated, this.onItemDeleted }); FeedFragment({ this.navigator, this.userData, this.onItemCreated, this.onItemDeleted });
=======
MeasurementRow({ Measurement measurement, this.onDismissed }) : this.measurement = measurement, super(key: new Key.stringify(measurement.when));
final Measurement measurement;
final MeasurementHandler onDismissed;
static const double kHeight = 79.0;
Widget build() {
List<Widget> children = [
new Flexible(
child: new Text(
measurement.displayWeight,
style: const TextStyle(textAlign: TextAlign.right)
)
),
new Flexible(
child: new Text(
measurement.displayDate,
style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
)
)
];
return new Dismissable(
key: new Key.stringify(measurement.when),
onDismissed: () => onDismissed(measurement),
child: new Card(
child: new Container(
height: kHeight,
padding: const EdgeDims.all(8.0),
child: new Flex(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(this).textBaseline
)
)
)
);
}
}
class HomeFragment extends StatefulComponent {
HomeFragment({ this.navigator, this.userData, this.onMeasurementCreated, this.onMeasurementDeleted });
>>>>>>> dk/master:sky/sdk/example/fitness/lib/home.dart
Navigator navigator; Navigator navigator;
List<FitnessItem> userData; List<FitnessItem> userData;
......
...@@ -27,6 +27,7 @@ class GameDemoWorld extends NodeWithSize { ...@@ -27,6 +27,7 @@ class GameDemoWorld extends NodeWithSize {
sky.Image _imgNebula; sky.Image _imgNebula;
SpriteSheet _spriteSheet; SpriteSheet _spriteSheet;
SpriteSheet _spriteSheetUI;
Navigator _navigator; Navigator _navigator;
// Inputs // Inputs
...@@ -46,8 +47,10 @@ class GameDemoWorld extends NodeWithSize { ...@@ -46,8 +47,10 @@ class GameDemoWorld extends NodeWithSize {
int _numFrames = 0; int _numFrames = 0;
bool _isGameOver = false; bool _isGameOver = false;
GameDemoWorld(App app, this._navigator, ImageMap images, this._spriteSheet) : super(new Size(_gameSizeWidth, _gameSizeHeight)) { // Heads up display
Hud _hud;
GameDemoWorld(App app, this._navigator, ImageMap images, this._spriteSheet, this._spriteSheetUI) : super(new Size(_gameSizeWidth, _gameSizeHeight)) {
// Fetch images // Fetch images
_imgNebula = images["assets/nebula.png"]; _imgNebula = images["assets/nebula.png"];
...@@ -81,6 +84,10 @@ class GameDemoWorld extends NodeWithSize { ...@@ -81,6 +84,10 @@ class GameDemoWorld extends NodeWithSize {
userInteractionEnabled = true; userInteractionEnabled = true;
handleMultiplePointers = true; handleMultiplePointers = true;
_hud = new Hud(_spriteSheetUI);
_hud.zPosition = 1000.0;
addChild(_hud);
} }
// Methods for adding game objects // Methods for adding game objects
...@@ -585,6 +592,52 @@ class StarField extends Node { ...@@ -585,6 +592,52 @@ class StarField extends Node {
} }
} }
class Hud extends NodeWithSize {
SpriteSheet spriteSheetUI;
Sprite sprtBgScore;
Sprite sprtBgShield;
int _score = 0;
int get score => _score;
set score(int score) {
_score = score;
_updateHud();
}
Hud(this.spriteSheetUI) {
pivot = Point.origin;
sprtBgScore = new Sprite(spriteSheetUI["scoreboard.png"]);
sprtBgScore.pivot = Point.origin;
sprtBgScore.scale = 0.6;
addChild(sprtBgScore);
sprtBgShield = new Sprite(spriteSheetUI["bar_shield.png"]);
sprtBgShield.pivot = new Point(1.0, 0.0);
sprtBgShield.scale = 0.6;
addChild(sprtBgShield);
}
void spriteBoxPerformedLayout() {
// Set the size and position of HUD display
position = spriteBox.visibleArea.topLeft;
size = spriteBox.visibleArea.size;
// Position hud objects
sprtBgScore.position = new Point(20.0, 20.0);
sprtBgShield.position = new Point(size.width - 20.0, 20.0);
}
void _updateHud() {
sprtBgScore.removeAllChildren();
String scoreStr = _score.toString();
}
}
class Nebula extends Node { class Nebula extends Node {
Nebula.withImage(sky.Image img) { Nebula.withImage(sky.Image img) {
......
...@@ -39,6 +39,7 @@ class SpriteBox extends RenderBox { ...@@ -39,6 +39,7 @@ class SpriteBox extends RenderBox {
// Add new references // Add new references
_addSpriteBoxReference(_rootNode); _addSpriteBoxReference(_rootNode);
markNeedsLayout();
} }
// Tracking of frame rate and updates // Tracking of frame rate and updates
...@@ -55,7 +56,7 @@ class SpriteBox extends RenderBox { ...@@ -55,7 +56,7 @@ class SpriteBox extends RenderBox {
_transformMode = value; _transformMode = value;
// Invalidate stuff // Invalidate stuff
if (attached) performLayout(); markNeedsLayout();
} }
/// The transform mode used by the [SpriteBox]. /// The transform mode used by the [SpriteBox].
...@@ -68,7 +69,11 @@ class SpriteBox extends RenderBox { ...@@ -68,7 +69,11 @@ class SpriteBox extends RenderBox {
Rect _visibleArea; Rect _visibleArea;
Rect get visibleArea => _visibleArea; Rect get visibleArea {
if (_visibleArea == null)
_calcTransformMatrix();
return _visibleArea;
}
// Setup // Setup
...@@ -131,7 +136,8 @@ class SpriteBox extends RenderBox { ...@@ -131,7 +136,8 @@ class SpriteBox extends RenderBox {
// Add childrens that are behind this node // Add childrens that are behind this node
while (i < children.length) { while (i < children.length) {
Node child = children[i]; Node child = children[i];
if (child.zPosition >= 0.0) break; if (child.zPosition >= 0.0)
break;
_addEventTargets(child, eventTargets); _addEventTargets(child, eventTargets);
i++; i++;
} }
...@@ -150,6 +156,9 @@ class SpriteBox extends RenderBox { ...@@ -150,6 +156,9 @@ class SpriteBox extends RenderBox {
} }
void handleEvent(Event event, _SpriteBoxHitTestEntry entry) { void handleEvent(Event event, _SpriteBoxHitTestEntry entry) {
if (!attached)
return;
if (event is PointerEvent) { if (event is PointerEvent) {
if (event.type == 'pointerdown') { if (event.type == 'pointerdown') {
...@@ -185,7 +194,8 @@ class SpriteBox extends RenderBox { ...@@ -185,7 +194,8 @@ class SpriteBox extends RenderBox {
if (node.handleMultiplePointers || event.pointer == node._handlingPointer) { if (node.handleMultiplePointers || event.pointer == node._handlingPointer) {
// Dispatch event // Dispatch event
bool consumedEvent = node.handleEvent(new SpriteBoxEvent(new Point(event.x, event.y), event.type, event.pointer)); bool consumedEvent = node.handleEvent(new SpriteBoxEvent(new Point(event.x, event.y), event.type, event.pointer));
if (consumedEvent == null || consumedEvent) break; if (consumedEvent == null || consumedEvent)
break;
} }
} }
...@@ -212,10 +222,13 @@ class SpriteBox extends RenderBox { ...@@ -212,10 +222,13 @@ class SpriteBox extends RenderBox {
/// var matrix = mySpriteBox.transformMatrix; /// var matrix = mySpriteBox.transformMatrix;
Matrix4 get transformMatrix { Matrix4 get transformMatrix {
// Get cached matrix if available // Get cached matrix if available
if (_transformMatrix != null) { if (_transformMatrix == null) {
_calcTransformMatrix();
}
return _transformMatrix; return _transformMatrix;
} }
void _calcTransformMatrix() {
_transformMatrix = new Matrix4.identity(); _transformMatrix = new Matrix4.identity();
// Calculate matrix // Calculate matrix
...@@ -273,13 +286,17 @@ class SpriteBox extends RenderBox { ...@@ -273,13 +286,17 @@ class SpriteBox extends RenderBox {
break; break;
} }
_visibleArea = new Rect.fromLTRB(-offsetX / scaleX,
-offsetY / scaleY,
systemWidth + offsetX / scaleX,
systemHeight + offsetY / scaleY);
_transformMatrix.translate(offsetX, offsetY); _transformMatrix.translate(offsetX, offsetY);
_transformMatrix.scale(scaleX, scaleY); _transformMatrix.scale(scaleX, scaleY);
return _transformMatrix;
} }
void _invalidateTransformMatrix() { void _invalidateTransformMatrix() {
_visibleArea = null;
_transformMatrix = null; _transformMatrix = null;
_rootNode._invalidateToBoxTransformMatrix(); _rootNode._invalidateToBoxTransformMatrix();
} }
...@@ -304,7 +321,8 @@ class SpriteBox extends RenderBox { ...@@ -304,7 +321,8 @@ class SpriteBox extends RenderBox {
} }
void _tick(double timeStamp) { void _tick(double timeStamp) {
if (!attached) return; if (!attached)
return;
// Calculate the time between frames in seconds // Calculate the time between frames in seconds
if (_lastTimeStamp == null) _lastTimeStamp = timeStamp; if (_lastTimeStamp == null) _lastTimeStamp = timeStamp;
...@@ -317,7 +335,8 @@ class SpriteBox extends RenderBox { ...@@ -317,7 +335,8 @@ class SpriteBox extends RenderBox {
_frameRate = 1.0/delta; _frameRate = 1.0/delta;
// Print frame rate // Print frame rate
if (_numFrames % 60 == 0) print("delta: $delta fps: $_frameRate"); if (_numFrames % 60 == 0)
print("delta: $delta fps: $_frameRate");
_runActions(_rootNode, delta); _runActions(_rootNode, delta);
_callUpdate(_rootNode, delta); _callUpdate(_rootNode, delta);
......
...@@ -51,6 +51,7 @@ main() async { ...@@ -51,6 +51,7 @@ main() async {
class GameDemoApp extends App { class GameDemoApp extends App {
NavigationState _navigationState; NavigationState _navigationState;
GameDemoWorld _game;
void initState() { void initState() {
_navigationState = new NavigationState([ _navigationState = new NavigationState([
...@@ -84,21 +85,18 @@ class GameDemoApp extends App { ...@@ -84,21 +85,18 @@ class GameDemoApp extends App {
} }
Widget _buildGameScene(navigator, route) { Widget _buildGameScene(navigator, route) {
return new SpriteWidget( return new SpriteWidget(_game);
new GameDemoWorld(_app, navigator, _loader, _spriteSheet)
);
} }
Widget _buildMainScene(navigator, route) { Widget _buildMainScene(navigator, route) {
return new Center( return new Center(
child: new RaisedButton( child: new RaisedButton(
child: new Text("Play"), child: new Text("Play"),
onPressed: () => navigator.pushNamed('/game') onPressed: () {
_game = new GameDemoWorld(_app, navigator, _loader, _spriteSheet, _spriteSheetUI);
navigator.pushNamed('/game');
}
) )
); );
} }
} }
void resetGame() {
_app.scheduleBuild();
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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.
...@@ -9,125 +8,167 @@ import 'package:sky/painting/text_style.dart'; ...@@ -9,125 +8,167 @@ import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/flex.dart'; import 'package:sky/rendering/flex.dart';
import 'package:sky/theme/colors.dart' as colors; import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/scaffold.dart'; import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/task_description.dart'; import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart'; import 'package:sky/widgets/tool_bar.dart';
// Classic minesweeper-inspired game. The mouse controls are standard except // Classic minesweeper-inspired game. The mouse controls are standard
// for left + right combo which is not implemented. For touch, the duration of // except for left + right combo which is not implemented. For touch,
// the pointer determines probing versus flagging. // the duration of the pointer determines probing versus flagging.
// //
// There are only 3 classes to understand. Game, which is contains all the // There are only 3 classes to understand. MineDiggerApp, which is
// logic and two UI classes: CoveredMineNode and ExposedMineNode, none of them // contains all the logic and two classes that describe the mines:
// holding state. // CoveredMineNode and ExposedMineNode, none of them holding state.
// Colors for each mine count (0-8):
const List<TextStyle> textStyles = const <TextStyle>[
const TextStyle(color: const Color(0xFF555555), fontWeight: bold),
const TextStyle(color: const Color(0xFF0094FF), fontWeight: bold), // blue
const TextStyle(color: const Color(0xFF13A023), fontWeight: bold), // green
const TextStyle(color: const Color(0xFFDA1414), fontWeight: bold), // red
const TextStyle(color: const Color(0xFF1E2347), fontWeight: bold), // black
const TextStyle(color: const Color(0xFF7F0037), fontWeight: bold), // dark red
const TextStyle(color: const Color(0xFF000000), fontWeight: bold),
const TextStyle(color: const Color(0xFF000000), fontWeight: bold),
const TextStyle(color: const Color(0xFF000000), fontWeight: bold),
];
enum CellState { covered, exploded, cleared, flagged, shown }
class MineDiggerApp extends App {
void initState() {
resetGame();
}
class Game {
static const int rows = 9; static const int rows = 9;
static const int cols = 9; static const int cols = 9;
static const int totalMineCount = 11; static const int totalMineCount = 11;
static const int coveredCell = 0;
static const int explodedCell = 1;
static const int clearedCell = 2;
static const int flaggedCell = 3;
static const int shownCell = 4;
static final List<TextStyle> textStyles = new List<TextStyle>();
final App app;
bool alive; bool alive;
bool hasWon; bool hasWon;
int detectedCount; int detectedCount;
int randomSeed;
// |cells| keeps track of the positions of the mines. // |cells| keeps track of the positions of the mines.
List<List<bool>> cells; List<List<bool>> cells;
// |uiState| keeps track of the visible player progess. // |uiState| keeps track of the visible player progess.
List<List<int>> uiState; List<List<CellState>> uiState;
Game(this.app) { Game(this.app) {
randomSeed = 22; randomSeed = 22;
// Colors for each mine count: // Colors for each mine count:
// 0 - none, 1 - blue, 2-green, 3-red, 4-black, 5-dark red .. etc. // 0 - none, 1 - blue, 2-green, 3-red, 4-black, 5-dark red .. etc.
textStyles.add( textStyles.add(new TextStyle(color: const Color(0xFF555555), fontWeight: bold));
new TextStyle(color: const Color(0xFF555555), fontWeight: bold)); textStyles.add(new TextStyle(color: const Color(0xFF0094FF), fontWeight: bold));
textStyles.add( textStyles.add(new TextStyle(color: const Color(0xFF13A023), fontWeight: bold));
new TextStyle(color: const Color(0xFF0094FF), fontWeight: bold)); textStyles.add(new TextStyle(color: const Color(0xFFDA1414), fontWeight: bold));
textStyles.add( textStyles.add(new TextStyle(color: const Color(0xFF1E2347), fontWeight: bold));
new TextStyle(color: const Color(0xFF13A023), fontWeight: bold)); textStyles.add(new TextStyle(color: const Color(0xFF7F0037), fontWeight: bold));
textStyles.add( textStyles.add(new TextStyle(color: const Color(0xFFE93BE9), fontWeight: bold));
new TextStyle(color: const Color(0xFFDA1414), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF1E2347), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFF7F0037), fontWeight: bold));
textStyles.add(
new TextStyle(color: const Color(0xFFE93BE9), fontWeight: bold));
initialize(); initialize();
} }
void initialize() { void resetGame() {
alive = true; alive = true;
hasWon = false; hasWon = false;
detectedCount = 0; detectedCount = 0;
// Build the arrays. // Build the arrays.
cells = new List<List<bool>>(); cells = new List<List<bool>>();
uiState = new List<List<int>>(); uiState = new List<List<CellState>>();
for (int iy = 0; iy != rows; iy++) { for (int iy = 0; iy != rows; iy++) {
cells.add(new List<bool>()); cells.add(new List<bool>());
uiState.add(new List<int>()); uiState.add(new List<CellState>());
for (int ix = 0; ix != cols; ix++) { for (int ix = 0; ix != cols; ix++) {
cells[iy].add(false); cells[iy].add(false);
uiState[iy].add(coveredCell); uiState[iy].add(CellState.covered);
} }
} }
// Place the mines. // Place the mines.
Random random = new Random(++randomSeed); Random random = new Random();
for (int mc = 0; mc != totalMineCount; mc++) { int cellsRemaining = rows * cols;
int rx = random.nextInt(rows); int minesRemaining = totalMineCount;
int ry = random.nextInt(cols); for (int x = 0; x < cols; x += 1) {
if (cells[ry][rx]) { for (int y = 0; y < rows; y += 1) {
// Mine already there. Try again. if (random.nextInt(cellsRemaining) < minesRemaining) {
--mc; cells[y][x] = true;
minesRemaining -= 1;
if (minesRemaining <= 0)
return;
}
cellsRemaining -= 1;
}
}
assert(false);
}
Stopwatch longPressStopwatch;
PointerEventListener _pointerDownHandlerFor(int posX, int posY) {
return (sky.PointerEvent event) {
if (event.buttons == 1) {
probe(posX, posY);
} else if (event.buttons == 2) {
flag(posX, posY);
} else { } else {
cells[ry][rx] = true; // Touch event.
longPressStopwatch = new Stopwatch()..start();
} }
};
} }
PointerEventListener _pointerUpHandlerFor(int posX, int posY) {
return (sky.PointerEvent event) {
if (longPressStopwatch == null)
return;
// Pointer down was a touch event.
if (longPressStopwatch.elapsedMilliseconds < 250) {
probe(posX, posY);
} else {
// Long press flags.
flag(posX, posY);
}
longPressStopwatch = null;
};
} }
Widget buildBoard() { Widget buildBoard() {
bool hasCoveredCell = false; bool hasCoveredCell = false;
List<Flex> flexRows = new List<Flex>(); List<Flex> flexRows = <Flex>[];
for (int iy = 0; iy != 9; iy++) { for (int iy = 0; iy != 9; iy++) {
List<Component> row = new List<Component>(); List<Widget> row = <Widget>[];
for (int ix = 0; ix != 9; ix++) { for (int ix = 0; ix != 9; ix++) {
int state = uiState[iy][ix]; CellState state = uiState[iy][ix];
int count = mineCount(ix, iy); int count = mineCount(ix, iy);
if (!alive) { if (!alive) {
if (state != explodedCell) if (state != CellState.exploded)
state = cells[iy][ix] ? shownCell : state; state = cells[iy][ix] ? CellState.shown : state;
} }
if (state == CellState.covered) {
if (state == coveredCell) { row.add(new Listener(
row.add(new CoveredMineNode( onPointerDown: _pointerDownHandlerFor(ix, iy),
this, onPointerUp: _pointerUpHandlerFor(ix, iy),
child: new CoveredMineNode(
flagged: false, flagged: false,
posX: ix, posY: iy)); posX: ix,
posY: iy
)
));
// Mutating |hasCoveredCell| here is hacky, but convenient, same // Mutating |hasCoveredCell| here is hacky, but convenient, same
// goes for mutating |hasWon| below. // goes for mutating |hasWon| below.
hasCoveredCell = true; hasCoveredCell = true;
} else if (state == flaggedCell) { } else if (state == CellState.flagged) {
row.add(new CoveredMineNode( row.add(new CoveredMineNode(
this,
flagged: true, flagged: true,
posX: ix, posY: iy)); posX: ix,
posY: iy
));
} else { } else {
row.add(new ExposedMineNode( row.add(new ExposedMineNode(
state: state, state: state,
count: count)); count: count
));
} }
} }
flexRows.add( flexRows.add(
...@@ -135,8 +176,9 @@ class Game { ...@@ -135,8 +176,9 @@ class Game {
row, row,
direction: FlexDirection.horizontal, direction: FlexDirection.horizontal,
justifyContent: FlexJustifyContent.center, justifyContent: FlexJustifyContent.center,
key: 'flex_row($iy)' key: new Key.stringify(iy)
)); )
);
} }
if (!hasCoveredCell) { if (!hasCoveredCell) {
...@@ -147,33 +189,32 @@ class Game { ...@@ -147,33 +189,32 @@ class Game {
} }
return new Container( return new Container(
key: 'minefield',
padding: new EdgeDims.all(10.0), padding: new EdgeDims.all(10.0),
margin: new EdgeDims.all(10.0), margin: new EdgeDims.all(10.0),
decoration: new BoxDecoration(backgroundColor: const Color(0xFF6B6B6B)), decoration: new BoxDecoration(backgroundColor: const Color(0xFF6B6B6B)),
child: new Flex( child: new Flex(
flexRows, flexRows,
direction: FlexDirection.vertical, direction: FlexDirection.vertical
key: 'flxv')); )
);
} }
Widget buildToolBar() { Widget buildToolBar() {
String banner = hasWon ? String toolbarCaption = hasWon ?
'Awesome!!' : alive ? 'Awesome!!' : alive ?
'Mine Digger [$detectedCount-$totalMineCount]': 'Kaboom! [press here]'; 'Mine Digger [$detectedCount-$totalMineCount]': 'Kaboom! [press here]';
return new ToolBar( return new ToolBar(
// FIXME: Strange to have the toolbar be tapable. // FIXME: Strange to have the toolbar be tapable.
center: new Listener( center: new Listener(
onPointerDown: handleBannerPointerDown, onPointerDown: handleToolbarPointerDown,
child: new Text(banner, style: Theme.of(this.app).text.title) child: new Text(toolbarCaption, style: Theme.of(this).text.title)
) )
); );
} }
Widget buildUI() { Widget build() {
// FIXME: We need to build the board before we build the toolbar because // We build the board before we build the toolbar because we compute the win state during build step.
// we compute the win state during build step.
Widget board = buildBoard(); Widget board = buildBoard();
return new TaskDescription( return new TaskDescription(
label: 'Mine Digger', label: 'Mine Digger',
...@@ -187,39 +228,42 @@ class Game { ...@@ -187,39 +228,42 @@ class Game {
); );
} }
void handleBannerPointerDown(sky.PointerEvent event) { void handleToolbarPointerDown(sky.PointerEvent event) {
initialize(); setState(() {
app.scheduleBuild(); resetGame();
});
} }
// User action. The user uncovers the cell which can cause losing the game. // User action. The user uncovers the cell which can cause losing the game.
void probe(int x, int y) { void probe(int x, int y) {
if (!alive) if (!alive)
return; return;
if (uiState[y][x] == flaggedCell) if (uiState[y][x] == CellState.flagged)
return; return;
setState(() {
// Allowed to probe. // Allowed to probe.
if (cells[y][x]) { if (cells[y][x]) {
// Probed on a mine --> dead!! // Probed on a mine --> dead!!
uiState[y][x] = explodedCell; uiState[y][x] = CellState.exploded;
alive = false; alive = false;
} else { } else {
// No mine, uncover nearby if possible. // No mine, uncover nearby if possible.
cull(x, y); cull(x, y);
} }
app.scheduleBuild(); });
} }
// User action. The user is sure a mine is at this location. // User action. The user is sure a mine is at this location.
void flag(int x, int y) { void flag(int x, int y) {
if (uiState[y][x] == flaggedCell) { setState(() {
uiState[y][x] = coveredCell; if (uiState[y][x] == CellState.flagged) {
uiState[y][x] = CellState.covered;
--detectedCount; --detectedCount;
} else { } else {
uiState[y][x] = flaggedCell; uiState[y][x] = CellState.flagged;
++detectedCount; ++detectedCount;
} }
app.scheduleBuild(); });
} }
// Recursively uncovers cells whose totalMineCount is zero. // Recursively uncovers cells whose totalMineCount is zero.
...@@ -229,9 +273,9 @@ class Game { ...@@ -229,9 +273,9 @@ class Game {
if ((y < 0) || (y > cols - 1)) if ((y < 0) || (y > cols - 1))
return; return;
if (uiState[y][x] == clearedCell) if (uiState[y][x] == CellState.cleared)
return; return;
uiState[y][x] = clearedCell; uiState[y][x] = CellState.cleared;
if (mineCount(x, y) > 0) if (mineCount(x, y) > 0)
return; return;
...@@ -269,106 +313,70 @@ class Game { ...@@ -269,106 +313,70 @@ class Game {
} }
} }
Widget makeCell(Widget widget) { Widget buildCell(Widget child) {
return new Container( return new Container(
padding: new EdgeDims.all(1.0), padding: new EdgeDims.all(1.0),
height: 27.0, width: 27.0, height: 27.0, width: 27.0,
decoration: new BoxDecoration(backgroundColor: const Color(0xFFC0C0C0)), decoration: new BoxDecoration(backgroundColor: const Color(0xFFC0C0C0)),
margin: new EdgeDims.all(2.0), margin: new EdgeDims.all(2.0),
child: widget); child: child
);
} }
Widget makeInnerCell(Widget widget) { Widget buildInnerCell(Widget child) {
return new Container( return new Container(
padding: new EdgeDims.all(1.0), padding: new EdgeDims.all(1.0),
margin: new EdgeDims.all(3.0), margin: new EdgeDims.all(3.0),
height: 17.0, width: 17.0, height: 17.0, width: 17.0,
child: widget); child: child
);
} }
class CoveredMineNode extends Component { class CoveredMineNode extends Component {
final Game game;
CoveredMineNode({ this.flagged, this.posX, this.posY });
final bool flagged; final bool flagged;
final int posX; final int posX;
final int posY; final int posY;
Stopwatch stopwatch;
CoveredMineNode(this.game, {this.flagged, this.posX, this.posY});
void _handlePointerDown(sky.PointerEvent event) {
if (event.buttons == 1) {
game.probe(posX, posY);
} else if (event.buttons == 2) {
game.flag(posX, posY);
} else {
// Touch event.
stopwatch = new Stopwatch()..start();
}
}
void _handlePointerUp(sky.PointerEvent event) {
if (stopwatch == null)
return;
// Pointer down was a touch event.
if (stopwatch.elapsedMilliseconds < 250) {
game.probe(posX, posY);
} else {
// Long press flags.
game.flag(posX, posY);
}
stopwatch = null;
}
Widget build() { Widget build() {
Widget text = flagged ? Widget text;
makeInnerCell(new StyledText(elements : [Game.textStyles[5], '\u2691'])) : if (flagged)
null; text = buildInnerCell(new StyledText(elements : [textStyles[5], '\u2691']));
Container inner = new Container( Container inner = new Container(
margin: new EdgeDims.all(2.0), margin: new EdgeDims.all(2.0),
height: 17.0, width: 17.0, height: 17.0, width: 17.0,
decoration: new BoxDecoration(backgroundColor: const Color(0xFFD9D9D9)), decoration: new BoxDecoration(backgroundColor: const Color(0xFFD9D9D9)),
child: text); child: text
);
return makeCell(new Listener( return buildCell(inner);
child: inner,
onPointerDown: _handlePointerDown,
onPointerUp: _handlePointerUp));
} }
} }
class ExposedMineNode extends Component { class ExposedMineNode extends Component {
final int state;
final int count;
ExposedMineNode({this.state, this.count}); ExposedMineNode({ this.state, this.count });
final CellState state;
final int count;
Widget build() { Widget build() {
StyledText text; StyledText text;
if (state == Game.clearedCell) { if (state == CellState.cleared) {
// Uncovered cell with nearby mine count. // Uncovered cell with nearby mine count.
if (count != 0) if (count != 0)
text = new StyledText(elements : [Game.textStyles[count], '$count']); text = new StyledText(elements : [textStyles[count], '$count']);
} else { } else {
// Exploded mine or shown mine for 'game over'. // Exploded mine or shown mine for 'game over'.
int color = state == Game.explodedCell ? 3 : 0; int color = state == CellState.exploded ? 3 : 0;
text = new StyledText(elements : [Game.textStyles[color], '\u2600']); text = new StyledText(elements : [textStyles[color], '\u2600']);
} }
return buildCell(buildInnerCell(text));
return makeCell(makeInnerCell(text));
}
}
class MineDiggerApp extends App {
Game game;
MineDiggerApp() {
game = new Game(this);
} }
Widget build() {
return game.buildUI();
}
} }
void main() { void main() {
......
...@@ -48,9 +48,12 @@ void doFrame(double timeStamp) { ...@@ -48,9 +48,12 @@ void doFrame(double timeStamp) {
node = root; node = root;
} else if (node != root && other != null && pickThis(0.1)) { } else if (node != root && other != null && pickThis(0.1)) {
report("insertBefore()"); report("insertBefore()");
try {
node.insertBefore([other]); node.insertBefore([other]);
} catch (_) {
}
break; break;
} else if (pickThis(0.001)) { } else if (node != root && pickThis(0.001)) {
report("remove()"); report("remove()");
node.remove(); node.remove();
} else if (node is sky.Element) { } else if (node is sky.Element) {
...@@ -148,7 +151,7 @@ void doFrame(double timeStamp) { ...@@ -148,7 +151,7 @@ void doFrame(double timeStamp) {
break; break;
} }
} else { } else {
assert(node is sky.Text); // assert(node is sky.Text);
final sky.Text text = node; final sky.Text text = node;
if (pickThis(0.1)) { if (pickThis(0.1)) {
report("appending a new text node (ASCII)"); report("appending a new text node (ASCII)");
......
...@@ -12,7 +12,7 @@ import 'package:sky/widgets/basic.dart'; ...@@ -12,7 +12,7 @@ import 'package:sky/widgets/basic.dart';
class StockArrow extends Component { class StockArrow extends Component {
StockArrow({ String key, this.percentChange }) : super(key: key); StockArrow({ Key key, this.percentChange }) : super(key: key);
final double percentChange; final double percentChange;
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:sky/editing/input.dart'; import 'package:sky/editing/input.dart';
import 'package:sky/animation/animated_value.dart';
import 'package:sky/widgets/animated_component.dart';
import 'package:sky/widgets/animation_builder.dart';
import 'package:sky/theme/colors.dart' as colors; import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/drawer.dart'; import 'package:sky/widgets/drawer.dart';
...@@ -35,7 +32,7 @@ typedef void ModeUpdater(StockMode mode); ...@@ -35,7 +32,7 @@ typedef void ModeUpdater(StockMode mode);
const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200); const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200);
class StockHome extends AnimatedComponent { class StockHome extends StatefulComponent {
StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater); StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater);
...@@ -54,7 +51,8 @@ class StockHome extends AnimatedComponent { ...@@ -54,7 +51,8 @@ class StockHome extends AnimatedComponent {
bool _isSearching = false; bool _isSearching = false;
String _searchQuery; String _searchQuery;
AnimationBuilder _snackbarTransform; SnackBarStatus _snackBarStatus = SnackBarStatus.inactive;
bool _isSnackBarShowing = false;
void _handleSearchBegin() { void _handleSearchBegin() {
navigator.pushState(this, (_) { navigator.pushState(this, (_) {
...@@ -69,7 +67,8 @@ class StockHome extends AnimatedComponent { ...@@ -69,7 +67,8 @@ class StockHome extends AnimatedComponent {
} }
void _handleSearchEnd() { void _handleSearchEnd() {
assert(navigator.currentRoute.key == this); assert(navigator.currentRoute is RouteState);
assert((navigator.currentRoute as RouteState).owner == this); // TODO(ianh): remove cast once analyzer is cleverer
navigator.pop(); navigator.pop();
setState(() { setState(() {
_isSearching = false; _isSearching = false;
...@@ -139,6 +138,7 @@ class StockHome extends AnimatedComponent { ...@@ -139,6 +138,7 @@ class StockHome extends AnimatedComponent {
Drawer buildDrawer() { Drawer buildDrawer() {
if (_drawerStatus == DrawerStatus.inactive) if (_drawerStatus == DrawerStatus.inactive)
return null; return null;
assert(_drawerShowing); // TODO(mpcomplete): this is always true
return new Drawer( return new Drawer(
level: 3, level: 3,
showing: _drawerShowing, showing: _drawerShowing,
...@@ -263,40 +263,34 @@ class StockHome extends AnimatedComponent { ...@@ -263,40 +263,34 @@ class StockHome extends AnimatedComponent {
void _handleUndo() { void _handleUndo() {
setState(() { setState(() {
_snackbarTransform = null; _isSnackBarShowing = false;
}); });
} }
Widget buildSnackBar() { Widget buildSnackBar() {
if (_snackbarTransform == null) if (_snackBarStatus == SnackBarStatus.inactive)
return null; return null;
return _snackbarTransform.build( return new SnackBar(
new SnackBar( showing: _isSnackBarShowing,
content: new Text("Stock purchased!"), content: new Text("Stock purchased!"),
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)] actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
)); onStatusChanged: (status) { setState(() { _snackBarStatus = status; }); }
);
} }
void _handleStockPurchased() { void _handleStockPurchased() {
setState(() { setState(() {
_snackbarTransform = new AnimationBuilder() _isSnackBarShowing = true;
..position = new AnimatedValue<Point>(const Point(0.0, 45.0), end: Point.origin); _snackBarStatus = SnackBarStatus.active;
var performance = _snackbarTransform.createPerformance(
[_snackbarTransform.position], duration: _kSnackbarSlideDuration);
watch(performance); // TODO(mpcomplete): need to unwatch
performance.play();
}); });
} }
Widget buildFloatingActionButton() { Widget buildFloatingActionButton() {
var widget = new FloatingActionButton( return new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24), child: new Icon(type: 'content/add', size: 24),
backgroundColor: colors.RedAccent[200], backgroundColor: colors.RedAccent[200],
onPressed: _handleStockPurchased onPressed: _handleStockPurchased
); );
if (_snackbarTransform != null)
widget = _snackbarTransform.build(widget);
return widget;
} }
void addMenuToOverlays(List<Widget> overlays) { void addMenuToOverlays(List<Widget> overlays) {
......
...@@ -10,7 +10,7 @@ import 'stock_data.dart'; ...@@ -10,7 +10,7 @@ import 'stock_data.dart';
import 'stock_row.dart'; import 'stock_row.dart';
class Stocklist extends Component { class Stocklist extends Component {
Stocklist({ String key, this.stocks }) : super(key: key); Stocklist({ Key key, this.stocks }) : super(key: key);
final List<Stock> stocks; final List<Stock> stocks;
......
...@@ -14,7 +14,7 @@ export 'package:sky/widgets/popup_menu.dart' show PopupMenuStatus; ...@@ -14,7 +14,7 @@ export 'package:sky/widgets/popup_menu.dart' show PopupMenuStatus;
class StockMenu extends Component { class StockMenu extends Component {
StockMenu({ StockMenu({
String key, Key key,
this.showing, this.showing,
this.onStatusChanged, this.onStatusChanged,
this.navigator, this.navigator,
......
...@@ -14,7 +14,7 @@ import 'stock_data.dart'; ...@@ -14,7 +14,7 @@ import 'stock_data.dart';
class StockRow extends Component { class StockRow extends Component {
StockRow({ Stock stock }) : this.stock = stock, super(key: stock.symbol); StockRow({ Stock stock }) : this.stock = stock, super(key: new Key(stock.symbol));
final Stock stock; final Stock stock;
......
...@@ -61,7 +61,7 @@ class StockSettings extends StatefulComponent { ...@@ -61,7 +61,7 @@ class StockSettings extends StatefulComponent {
break; break;
case StockMode.pessimistic: case StockMode.pessimistic:
showModeDialog = true; showModeDialog = true;
navigator.pushState("/settings/confirm", (_) { navigator.pushState(this, (_) {
showModeDialog = false; showModeDialog = false;
}); });
break; break;
......
...@@ -115,7 +115,7 @@ class BlockViewportApp extends App { ...@@ -115,7 +115,7 @@ class BlockViewportApp extends App {
if (index >= lengths.length) if (index >= lengths.length)
return null; return null;
return new Listener( return new Listener(
key: lengths[index].toString(), key: new Key.stringify(lengths[index]),
child: new Container( child: new Container(
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundColor: new Color((0xFF000000 + 0xFFFFFF * lengths[index] / kMaxLength).round()) backgroundColor: new Color((0xFF000000 + 0xFFFFFF * lengths[index] / kMaxLength).round())
......
...@@ -27,15 +27,13 @@ class CardModel { ...@@ -27,15 +27,13 @@ class CardModel {
Color color; Color color;
AnimationPerformance performance; AnimationPerformance performance;
String get label => "Item $value"; String get label => "Item $value";
String get key => value.toString(); Key get key => new Key.fromObjectIdentity(this);
bool operator ==(other) => other is CardModel && other.value == value;
int get hashCode => 373 * 37 * value.hashCode;
} }
class ShrinkingCard extends AnimatedComponent { class ShrinkingCard extends AnimatedComponent {
ShrinkingCard({ ShrinkingCard({
String key, Key key,
CardModel this.card, CardModel this.card,
Function this.onUpdated, Function this.onUpdated,
Function this.onCompleted Function this.onCompleted
......
...@@ -24,7 +24,7 @@ void addFlexChildSolidColor(RenderFlex parent, sky.Color backgroundColor, { int ...@@ -24,7 +24,7 @@ void addFlexChildSolidColor(RenderFlex parent, sky.Color backgroundColor, { int
// Solid colour, Widget version // Solid colour, Widget version
class Rectangle extends Component { class Rectangle extends Component {
Rectangle(this.color, { String key }) : super(key: key); Rectangle(this.color, { Key key }) : super(key: key);
final Color color; final Color color;
Widget build() { Widget build() {
return new Flexible( return new Flexible(
......
...@@ -52,7 +52,7 @@ HAL: This mission is too important for me to allow you to jeopardize it.'''; ...@@ -52,7 +52,7 @@ HAL: This mission is too important for me to allow you to jeopardize it.''';
Component toStyledText(String name, String text) { Component toStyledText(String name, String text) {
TextStyle lineStyle = (name == "Dave") ? daveStyle : halStyle; TextStyle lineStyle = (name == "Dave") ? daveStyle : halStyle;
return new StyledText( return new StyledText(
key: text, key: new Key(text),
elements: [lineStyle, [boldStyle, [underlineStyle, name], ":"], text] elements: [lineStyle, [boldStyle, [underlineStyle, name], ":"], text]
); );
} }
......
...@@ -54,11 +54,12 @@ class Timeline { ...@@ -54,11 +54,12 @@ class Timeline {
double end: 1.0 double end: 1.0
}) { }) {
assert(!_animation.isAnimating); assert(!_animation.isAnimating);
assert(duration > Duration.ZERO);
return _animation.start(new TweenSimulation(duration, begin, end)); return _animation.start(new TweenSimulation(duration, begin, end));
} }
Future animateTo(double target, { Duration duration }) { Future animateTo(double target, { Duration duration }) {
assert(duration > Duration.ZERO);
return _start(duration: duration, begin: value, end: target); return _start(duration: duration, begin: value, end: target);
} }
......
...@@ -18,7 +18,7 @@ const _kCursorWidth = 1.0; ...@@ -18,7 +18,7 @@ const _kCursorWidth = 1.0;
class EditableText extends StatefulComponent { class EditableText extends StatefulComponent {
EditableText({ EditableText({
String key, Key key,
this.value, this.value,
this.focused: false, this.focused: false,
this.style, this.style,
......
...@@ -25,7 +25,7 @@ class Input extends StatefulComponent { ...@@ -25,7 +25,7 @@ class Input extends StatefulComponent {
// Never makes sense to have both a localKey and a globalKey. // Never makes sense to have both a localKey and a globalKey.
// Possibly a class HeroKey who functions as a UUID. // Possibly a class HeroKey who functions as a UUID.
Input({String key, Input({Key key,
this.placeholder, this.placeholder,
this.onChanged, this.onChanged,
this.focused}) this.focused})
...@@ -75,7 +75,7 @@ class Input extends StatefulComponent { ...@@ -75,7 +75,7 @@ class Input extends StatefulComponent {
if (placeholder != null && _value.isEmpty) { if (placeholder != null && _value.isEmpty) {
Widget child = new Opacity( Widget child = new Opacity(
key: "placeholder", key: new Key('placeholder'),
child: new Text(placeholder, style: textStyle), child: new Text(placeholder, style: textStyle),
opacity: themeData.hintOpacity opacity: themeData.hintOpacity
); );
......
...@@ -23,6 +23,7 @@ SKY_SERVER_PORT = 9888 ...@@ -23,6 +23,7 @@ SKY_SERVER_PORT = 9888
OBSERVATORY_PORT = 8181 OBSERVATORY_PORT = 8181
APK_NAME = 'SkyDemo.apk' APK_NAME = 'SkyDemo.apk'
ANDROID_PACKAGE = "org.domokit.sky.demo" ANDROID_PACKAGE = "org.domokit.sky.demo"
ANDROID_COMPONENT = '%s/%s.SkyDemoActivity' % (ANDROID_PACKAGE, ANDROID_PACKAGE)
# FIXME: This assumes adb is in $PATH, we could look for ANDROID_HOME, etc? # FIXME: This assumes adb is in $PATH, we could look for ANDROID_HOME, etc?
ADB_PATH = 'adb' ADB_PATH = 'adb'
# FIXME: Do we need to look in $DART_SDK? # FIXME: Do we need to look in $DART_SDK?
...@@ -111,7 +112,7 @@ class Pids(object): ...@@ -111,7 +112,7 @@ class Pids(object):
def _url_for_path(port, root, path): def _url_for_path(port, root, path):
relative_path = os.path.relpath(path, root) relative_path = os.path.relpath(path, root)
return 'sky://localhost:%s/%s' % (port, relative_path) return 'http://localhost:%s/%s' % (port, relative_path)
class StartSky(object): class StartSky(object):
...@@ -193,13 +194,14 @@ class StartSky(object): ...@@ -193,13 +194,14 @@ class StartSky(object):
pids['remote_sky_server_port'] = sky_server_port pids['remote_sky_server_port'] = sky_server_port
# The load happens on the remote device, use the remote port. # The load happens on the remote device, use the remote port.
sky_url = _url_for_path(pids['remote_sky_server_port'], sky_server_root, url = _url_for_path(pids['remote_sky_server_port'], sky_server_root,
main_dart) main_dart)
subprocess.check_call([ADB_PATH, 'shell', subprocess.check_call([ADB_PATH, 'shell',
'am', 'start', 'am', 'start',
'-a', 'android.intent.action.VIEW', '-a', 'android.intent.action.VIEW',
'-d', sky_url]) '-d', url,
ANDROID_COMPONENT])
class StopSky(object): class StopSky(object):
......
...@@ -7,7 +7,7 @@ import 'package:sky/widgets/basic.dart'; ...@@ -7,7 +7,7 @@ import 'package:sky/widgets/basic.dart';
abstract class AnimatedComponent extends StatefulComponent { abstract class AnimatedComponent extends StatefulComponent {
AnimatedComponent({ String key }) : super(key: key); AnimatedComponent({ Key key }) : super(key: key);
void syncFields(AnimatedComponent source) { } void syncFields(AnimatedComponent source) { }
......
...@@ -77,7 +77,7 @@ class ImplicitlyAnimatedValue<T> { ...@@ -77,7 +77,7 @@ class ImplicitlyAnimatedValue<T> {
class AnimatedContainer extends AnimatedComponent { class AnimatedContainer extends AnimatedComponent {
AnimatedContainer({ AnimatedContainer({
String key, Key key,
this.child, this.child,
this.duration, this.duration,
this.constraints, this.constraints,
......
// 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:vector_math/vector_math.dart';
import 'package:sky/animation/animated_value.dart';
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/painting/box_painter.dart';
import 'package:sky/theme/shadows.dart';
import 'package:sky/widgets/basic.dart';
// This class builds a Container object from a collection of optionally-
// animated properties. Use syncFields to update the Container's properties,
// which will optionally animate them using an AnimationPerformance.
class AnimationBuilder {
AnimationBuilder();
AnimatedValue<double> opacity;
AnimatedValue<Point> position;
AnimatedValue<double> shadow;
AnimatedColor backgroundColor;
// These don't animate, but are used to build the AnimationBuilder anyway.
double borderRadius;
Shape shape;
Map<AnimatedVariable, AnimationPerformance> _variableToPerformance =
new Map<AnimatedVariable, AnimationPerformance>();
AnimationPerformance createPerformance(List<AnimatedValue> variables,
{ Duration duration }) {
AnimationPerformance performance = new AnimationPerformance()
..duration = duration
..variable = new AnimatedList(variables);
for (AnimatedVariable variable in variables)
_variableToPerformance[variable] = performance;
return performance;
}
Widget build(Widget child) {
Widget current = child;
if (shadow != null || backgroundColor != null ||
borderRadius != null || shape != null) {
current = new DecoratedBox(
decoration: new BoxDecoration(
borderRadius: borderRadius,
shape: shape,
boxShadow: shadow != null ? _computeShadow(shadow.value) : null,
backgroundColor: backgroundColor != null ? backgroundColor.value : null),
child: current);
}
if (position != null) {
Matrix4 transform = new Matrix4.identity();
transform.translate(position.value.x, position.value.y);
current = new Transform(transform: transform, child: current);
}
if (opacity != null) {
current = new Opacity(opacity: opacity.value, child: current);
}
return current;
}
void updateFields({
AnimatedValue<double> shadow,
AnimatedColor backgroundColor,
double borderRadius,
Shape shape
}) {
_updateField(this.shadow, shadow);
_updateField(this.backgroundColor, backgroundColor);
this.borderRadius = borderRadius;
this.shape = shape;
}
void _updateField(AnimatedValue variable, AnimatedValue sourceVariable) {
if (variable == null)
return; // TODO(mpcomplete): Should we handle transition from null?
AnimationPerformance performance = _variableToPerformance[variable];
if (performance == null) {
// If there's no performance, no need to animate.
if (sourceVariable != null)
variable.value = sourceVariable.value;
return;
}
if (variable.value != sourceVariable.value) {
variable
..begin = variable.value
..end = sourceVariable.value;
performance
..progress = 0.0
..play();
}
}
}
List<BoxShadow> _computeShadow(double level) {
if (level < 1.0) // shadows[1] is the first shadow
return null;
int level1 = level.floor();
int level2 = level.ceil();
double t = level - level1.toDouble();
List<BoxShadow> shadow = new List<BoxShadow>();
for (int i = 0; i < shadows[level1].length; ++i)
shadow.add(lerpBoxShadow(shadows[level1][i], shadows[level2][i], t));
return shadow;
}
...@@ -22,13 +22,13 @@ import 'package:sky/widgets/widget.dart'; ...@@ -22,13 +22,13 @@ import 'package:sky/widgets/widget.dart';
export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims; export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems; export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems;
export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path; export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
export 'package:sky/widgets/widget.dart' show Widget, Component, StatefulComponent, App, runApp, Listener, ParentDataNode; export 'package:sky/widgets/widget.dart' show Key, Widget, Component, StatefulComponent, App, runApp, Listener, ParentDataNode;
// PAINTING NODES // PAINTING NODES
class Opacity extends OneChildRenderObjectWrapper { class Opacity extends OneChildRenderObjectWrapper {
Opacity({ String key, this.opacity, Widget child }) Opacity({ Key key, this.opacity, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double opacity; final double opacity;
...@@ -43,7 +43,7 @@ class Opacity extends OneChildRenderObjectWrapper { ...@@ -43,7 +43,7 @@ class Opacity extends OneChildRenderObjectWrapper {
} }
class ColorFilter extends OneChildRenderObjectWrapper { class ColorFilter extends OneChildRenderObjectWrapper {
ColorFilter({ String key, this.color, this.transferMode, Widget child }) ColorFilter({ Key key, this.color, this.transferMode, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final Color color; final Color color;
...@@ -60,7 +60,7 @@ class ColorFilter extends OneChildRenderObjectWrapper { ...@@ -60,7 +60,7 @@ class ColorFilter extends OneChildRenderObjectWrapper {
} }
class DecoratedBox extends OneChildRenderObjectWrapper { class DecoratedBox extends OneChildRenderObjectWrapper {
DecoratedBox({ String key, this.decoration, Widget child }) DecoratedBox({ Key key, this.decoration, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final BoxDecoration decoration; final BoxDecoration decoration;
...@@ -75,7 +75,7 @@ class DecoratedBox extends OneChildRenderObjectWrapper { ...@@ -75,7 +75,7 @@ class DecoratedBox extends OneChildRenderObjectWrapper {
} }
class CustomPaint extends OneChildRenderObjectWrapper { class CustomPaint extends OneChildRenderObjectWrapper {
CustomPaint({ String key, this.callback, this.token, Widget child }) CustomPaint({ Key key, this.callback, this.token, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final CustomPaintCallback callback; final CustomPaintCallback callback;
...@@ -98,7 +98,7 @@ class CustomPaint extends OneChildRenderObjectWrapper { ...@@ -98,7 +98,7 @@ class CustomPaint extends OneChildRenderObjectWrapper {
} }
class ClipRect extends OneChildRenderObjectWrapper { class ClipRect extends OneChildRenderObjectWrapper {
ClipRect({ String key, Widget child }) ClipRect({ Key key, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
RenderClipRect createNode() => new RenderClipRect(); RenderClipRect createNode() => new RenderClipRect();
...@@ -108,7 +108,7 @@ class ClipRect extends OneChildRenderObjectWrapper { ...@@ -108,7 +108,7 @@ class ClipRect extends OneChildRenderObjectWrapper {
} }
class ClipRRect extends OneChildRenderObjectWrapper { class ClipRRect extends OneChildRenderObjectWrapper {
ClipRRect({ String key, this.xRadius, this.yRadius, Widget child }) ClipRRect({ Key key, this.xRadius, this.yRadius, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double xRadius; final double xRadius;
...@@ -125,7 +125,7 @@ class ClipRRect extends OneChildRenderObjectWrapper { ...@@ -125,7 +125,7 @@ class ClipRRect extends OneChildRenderObjectWrapper {
} }
class ClipOval extends OneChildRenderObjectWrapper { class ClipOval extends OneChildRenderObjectWrapper {
ClipOval({ String key, Widget child }) ClipOval({ Key key, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
RenderClipOval createNode() => new RenderClipOval(); RenderClipOval createNode() => new RenderClipOval();
...@@ -138,7 +138,7 @@ class ClipOval extends OneChildRenderObjectWrapper { ...@@ -138,7 +138,7 @@ class ClipOval extends OneChildRenderObjectWrapper {
// POSITIONING AND SIZING NODES // POSITIONING AND SIZING NODES
class Transform extends OneChildRenderObjectWrapper { class Transform extends OneChildRenderObjectWrapper {
Transform({ String key, this.transform, Widget child }) Transform({ Key key, this.transform, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final Matrix4 transform; final Matrix4 transform;
...@@ -153,7 +153,7 @@ class Transform extends OneChildRenderObjectWrapper { ...@@ -153,7 +153,7 @@ class Transform extends OneChildRenderObjectWrapper {
} }
class Padding extends OneChildRenderObjectWrapper { class Padding extends OneChildRenderObjectWrapper {
Padding({ String key, this.padding, Widget child }) Padding({ Key key, this.padding, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final EdgeDims padding; final EdgeDims padding;
...@@ -168,7 +168,7 @@ class Padding extends OneChildRenderObjectWrapper { ...@@ -168,7 +168,7 @@ class Padding extends OneChildRenderObjectWrapper {
} }
class Center extends OneChildRenderObjectWrapper { class Center extends OneChildRenderObjectWrapper {
Center({ String key, Widget child }) Center({ Key key, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
RenderPositionedBox createNode() => new RenderPositionedBox(); RenderPositionedBox createNode() => new RenderPositionedBox();
...@@ -178,7 +178,7 @@ class Center extends OneChildRenderObjectWrapper { ...@@ -178,7 +178,7 @@ class Center extends OneChildRenderObjectWrapper {
} }
class SizedBox extends OneChildRenderObjectWrapper { class SizedBox extends OneChildRenderObjectWrapper {
SizedBox({ String key, this.width, this.height, Widget child }) SizedBox({ Key key, this.width, this.height, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double width; final double width;
...@@ -203,7 +203,7 @@ class SizedBox extends OneChildRenderObjectWrapper { ...@@ -203,7 +203,7 @@ class SizedBox extends OneChildRenderObjectWrapper {
} }
class ConstrainedBox extends OneChildRenderObjectWrapper { class ConstrainedBox extends OneChildRenderObjectWrapper {
ConstrainedBox({ String key, this.constraints, Widget child }) ConstrainedBox({ Key key, this.constraints, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final BoxConstraints constraints; final BoxConstraints constraints;
...@@ -218,7 +218,7 @@ class ConstrainedBox extends OneChildRenderObjectWrapper { ...@@ -218,7 +218,7 @@ class ConstrainedBox extends OneChildRenderObjectWrapper {
} }
class AspectRatio extends OneChildRenderObjectWrapper { class AspectRatio extends OneChildRenderObjectWrapper {
AspectRatio({ String key, this.aspectRatio, Widget child }) AspectRatio({ Key key, this.aspectRatio, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double aspectRatio; final double aspectRatio;
...@@ -233,7 +233,7 @@ class AspectRatio extends OneChildRenderObjectWrapper { ...@@ -233,7 +233,7 @@ class AspectRatio extends OneChildRenderObjectWrapper {
} }
class ShrinkWrapWidth extends OneChildRenderObjectWrapper { class ShrinkWrapWidth extends OneChildRenderObjectWrapper {
ShrinkWrapWidth({ String key, this.stepWidth, this.stepHeight, Widget child }) ShrinkWrapWidth({ Key key, this.stepWidth, this.stepHeight, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double stepWidth; final double stepWidth;
...@@ -250,7 +250,7 @@ class ShrinkWrapWidth extends OneChildRenderObjectWrapper { ...@@ -250,7 +250,7 @@ class ShrinkWrapWidth extends OneChildRenderObjectWrapper {
} }
class Baseline extends OneChildRenderObjectWrapper { class Baseline extends OneChildRenderObjectWrapper {
Baseline({ String key, this.baseline, this.baselineType: TextBaseline.alphabetic, Widget child }) Baseline({ Key key, this.baseline, this.baselineType: TextBaseline.alphabetic, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double baseline; // in pixels final double baseline; // in pixels
...@@ -267,7 +267,7 @@ class Baseline extends OneChildRenderObjectWrapper { ...@@ -267,7 +267,7 @@ class Baseline extends OneChildRenderObjectWrapper {
} }
class Viewport extends OneChildRenderObjectWrapper { class Viewport extends OneChildRenderObjectWrapper {
Viewport({ String key, this.offset: 0.0, Widget child }) Viewport({ Key key, this.offset: 0.0, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final double offset; final double offset;
...@@ -282,7 +282,7 @@ class Viewport extends OneChildRenderObjectWrapper { ...@@ -282,7 +282,7 @@ class Viewport extends OneChildRenderObjectWrapper {
} }
class SizeObserver extends OneChildRenderObjectWrapper { class SizeObserver extends OneChildRenderObjectWrapper {
SizeObserver({ String key, this.callback, Widget child }) SizeObserver({ Key key, this.callback, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
final SizeChangedCallback callback; final SizeChangedCallback callback;
...@@ -307,7 +307,7 @@ class SizeObserver extends OneChildRenderObjectWrapper { ...@@ -307,7 +307,7 @@ class SizeObserver extends OneChildRenderObjectWrapper {
class Container extends Component { class Container extends Component {
Container({ Container({
String key, Key key,
this.child, this.child,
this.constraints, this.constraints,
this.decoration, this.decoration,
...@@ -364,7 +364,7 @@ class Container extends Component { ...@@ -364,7 +364,7 @@ class Container extends Component {
// LAYOUT NODES // LAYOUT NODES
class Block extends MultiChildRenderObjectWrapper { class Block extends MultiChildRenderObjectWrapper {
Block(List<Widget> children, { String key }) Block(List<Widget> children, { Key key })
: super(key: key, children: children); : super(key: key, children: children);
RenderBlock createNode() => new RenderBlock(); RenderBlock createNode() => new RenderBlock();
...@@ -372,7 +372,7 @@ class Block extends MultiChildRenderObjectWrapper { ...@@ -372,7 +372,7 @@ class Block extends MultiChildRenderObjectWrapper {
} }
class Stack extends MultiChildRenderObjectWrapper { class Stack extends MultiChildRenderObjectWrapper {
Stack(List<Widget> children, { String key }) Stack(List<Widget> children, { Key key })
: super(key: key, children: children); : super(key: key, children: children);
RenderStack createNode() => new RenderStack(); RenderStack createNode() => new RenderStack();
...@@ -381,7 +381,7 @@ class Stack extends MultiChildRenderObjectWrapper { ...@@ -381,7 +381,7 @@ class Stack extends MultiChildRenderObjectWrapper {
class Positioned extends ParentDataNode { class Positioned extends ParentDataNode {
Positioned({ Positioned({
String key, Key key,
Widget child, Widget child,
double top, double top,
double right, double right,
...@@ -398,7 +398,7 @@ class Positioned extends ParentDataNode { ...@@ -398,7 +398,7 @@ class Positioned extends ParentDataNode {
class Flex extends MultiChildRenderObjectWrapper { class Flex extends MultiChildRenderObjectWrapper {
Flex(List<Widget> children, { Flex(List<Widget> children, {
String key, Key key,
this.direction: FlexDirection.horizontal, this.direction: FlexDirection.horizontal,
this.justifyContent: FlexJustifyContent.start, this.justifyContent: FlexJustifyContent.start,
this.alignItems: FlexAlignItems.center, this.alignItems: FlexAlignItems.center,
...@@ -424,12 +424,12 @@ class Flex extends MultiChildRenderObjectWrapper { ...@@ -424,12 +424,12 @@ class Flex extends MultiChildRenderObjectWrapper {
} }
class Flexible extends ParentDataNode { class Flexible extends ParentDataNode {
Flexible({ String key, int flex: 1, Widget child }) Flexible({ Key key, int flex: 1, Widget child })
: super(child, new FlexBoxParentData()..flex = flex, key: key); : super(child, new FlexBoxParentData()..flex = flex, key: key);
} }
class Inline extends LeafRenderObjectWrapper { class Inline extends LeafRenderObjectWrapper {
Inline({ String key, this.text }) : super(key: key); Inline({ Key key, this.text }) : super(key: key);
final InlineBase text; final InlineBase text;
...@@ -446,7 +446,7 @@ class StyledText extends Component { ...@@ -446,7 +446,7 @@ class StyledText extends Component {
// elements ::= "string" | [<text-style> <elements>*] // elements ::= "string" | [<text-style> <elements>*]
// Where "string" is text to display and text-style is an instance of // Where "string" is text to display and text-style is an instance of
// TextStyle. The text-style applies to all of the elements that follow. // TextStyle. The text-style applies to all of the elements that follow.
StyledText({ this.elements, String key }) : super(key: key); StyledText({ this.elements, Key key }) : super(key: key);
final dynamic elements; final dynamic elements;
...@@ -464,7 +464,7 @@ class StyledText extends Component { ...@@ -464,7 +464,7 @@ class StyledText extends Component {
} }
class Text extends Component { class Text extends Component {
Text(this.data, { String key, TextStyle this.style }) : super(key: key); Text(this.data, { Key key, TextStyle this.style }) : super(key: key);
final String data; final String data;
final TextStyle style; final TextStyle style;
...@@ -488,9 +488,7 @@ class Text extends Component { ...@@ -488,9 +488,7 @@ class Text extends Component {
} }
class Image extends LeafRenderObjectWrapper { class Image extends LeafRenderObjectWrapper {
Image({ sky.Image image, this.width, this.height, this.colorFilter }) Image({ Key key, this.image, this.width, this.height, this.colorFilter }) : super(key: key);
: image = image,
super(key: image.hashCode.toString()); // TODO(ianh): Find a way to uniquely identify the sky.Image rather than using hashCode, which could collide
final sky.Image image; final sky.Image image;
final double width; final double width;
...@@ -510,8 +508,7 @@ class Image extends LeafRenderObjectWrapper { ...@@ -510,8 +508,7 @@ class Image extends LeafRenderObjectWrapper {
} }
class FutureImage extends StatefulComponent { class FutureImage extends StatefulComponent {
FutureImage({ String key, this.image, this.width, this.height, this.colorFilter }) FutureImage({ Key key, this.image, this.width, this.height, this.colorFilter }) : super(key: key);
: super(key: key);
Future<sky.Image> image; Future<sky.Image> image;
double width; double width;
...@@ -555,8 +552,7 @@ class FutureImage extends StatefulComponent { ...@@ -555,8 +552,7 @@ class FutureImage extends StatefulComponent {
} }
class NetworkImage extends Component { class NetworkImage extends Component {
NetworkImage({ String src, this.width, this.height, this.colorFilter }) NetworkImage({ Key key, this.src, this.width, this.height, this.colorFilter }) : super(key: key);
: src = src, super(key: src);
final String src; final String src;
final double width; final double width;
...@@ -574,9 +570,7 @@ class NetworkImage extends Component { ...@@ -574,9 +570,7 @@ class NetworkImage extends Component {
} }
class AssetImage extends Component { class AssetImage extends Component {
AssetImage({ String name, this.bundle, this.width, this.height, this.colorFilter }) AssetImage({ Key key, this.name, this.bundle, this.width, this.height, this.colorFilter }) : super(key: key);
: name = name,
super(key: name);
final String name; final String name;
final AssetBundle bundle; final AssetBundle bundle;
...@@ -597,7 +591,7 @@ class AssetImage extends Component { ...@@ -597,7 +591,7 @@ class AssetImage extends Component {
class WidgetToRenderBoxAdapter extends LeafRenderObjectWrapper { class WidgetToRenderBoxAdapter extends LeafRenderObjectWrapper {
WidgetToRenderBoxAdapter(RenderBox renderBox) WidgetToRenderBoxAdapter(RenderBox renderBox)
: renderBox = renderBox, : renderBox = renderBox,
super(key: renderBox.hashCode.toString()); // TODO(ianh): Find a way to uniquely identify the RenderBox rather than using hashCode, which could collide super(key: new Key.fromObjectIdentity(renderBox));
final RenderBox renderBox; final RenderBox renderBox;
......
...@@ -16,7 +16,7 @@ class _Key { ...@@ -16,7 +16,7 @@ class _Key {
const _Key(this.type, this.key); const _Key(this.type, this.key);
factory _Key.fromWidget(Widget widget) => new _Key(widget.runtimeType, widget.key); factory _Key.fromWidget(Widget widget) => new _Key(widget.runtimeType, widget.key);
final Type type; final Type type;
final String key; final Key key;
bool operator ==(other) => other is _Key && other.type == type && other.key == key; bool operator ==(other) => other is _Key && other.type == type && other.key == key;
int get hashCode => 373 * 37 * type.hashCode + key.hashCode; int get hashCode => 373 * 37 * type.hashCode + key.hashCode;
String toString() => "_Key(type: $type, key: $key)"; String toString() => "_Key(type: $type, key: $key)";
...@@ -78,7 +78,7 @@ class BlockViewportLayoutState { ...@@ -78,7 +78,7 @@ class BlockViewportLayoutState {
} }
class BlockViewport extends RenderObjectWrapper { class BlockViewport extends RenderObjectWrapper {
BlockViewport({ this.builder, this.startOffset, this.token, this.layoutState, String key }) BlockViewport({ this.builder, this.startOffset, this.token, this.layoutState, Key key })
: super(key: key) { : super(key: key) {
assert(this.layoutState != null); assert(this.layoutState != null);
} }
......
...@@ -6,7 +6,7 @@ import 'package:sky/widgets/basic.dart'; ...@@ -6,7 +6,7 @@ import 'package:sky/widgets/basic.dart';
abstract class ButtonBase extends StatefulComponent { abstract class ButtonBase extends StatefulComponent {
ButtonBase({ String key, this.highlight: false }) : super(key: key); ButtonBase({ Key key, this.highlight: false }) : super(key: key);
bool highlight; bool highlight;
......
...@@ -11,7 +11,7 @@ const EdgeDims kCardMargins = const EdgeDims.all(4.0); ...@@ -11,7 +11,7 @@ const EdgeDims kCardMargins = const EdgeDims.all(4.0);
/// ///
/// <https://www.google.com/design/spec/components/cards.html> /// <https://www.google.com/design/spec/components/cards.html>
class Card extends Component { class Card extends Component {
Card({ String key, this.child, this.color }) : super(key: key); Card({ Key key, this.child, this.color }) : super(key: key);
final Widget child; final Widget child;
final Color color; final Color color;
......
...@@ -32,7 +32,7 @@ class Checkbox extends Toggleable { ...@@ -32,7 +32,7 @@ class Checkbox extends Toggleable {
/// * `value` determines whether the checkbox is checked. /// * `value` determines whether the checkbox is checked.
/// * `onChanged` is called whenever the state of the checkbox should change. /// * `onChanged` is called whenever the state of the checkbox should change.
Checkbox({ Checkbox({
String key, Key key,
bool value, bool value,
ValueChanged onChanged ValueChanged onChanged
}) : super(key: key, value: value, onChanged: onChanged); }) : super(key: key, value: value, onChanged: onChanged);
......
...@@ -9,7 +9,7 @@ import 'package:sky/widgets/widget.dart'; ...@@ -9,7 +9,7 @@ import 'package:sky/widgets/widget.dart';
class DefaultTextStyle extends Inherited { class DefaultTextStyle extends Inherited {
DefaultTextStyle({ DefaultTextStyle({
String key, Key key,
this.style, this.style,
Widget child Widget child
}) : super(key: key, child: child) { }) : super(key: key, child: child) {
......
...@@ -14,7 +14,7 @@ import 'package:sky/widgets/theme.dart'; ...@@ -14,7 +14,7 @@ import 'package:sky/widgets/theme.dart';
/// <https://www.google.com/design/spec/components/dialogs.html> /// <https://www.google.com/design/spec/components/dialogs.html>
class Dialog extends Component { class Dialog extends Component {
Dialog({ Dialog({
String key, Key key,
this.title, this.title,
this.content, this.content,
this.actions, this.actions,
......
...@@ -22,7 +22,7 @@ typedef void DismissedCallback(); ...@@ -22,7 +22,7 @@ typedef void DismissedCallback();
class Dismissable extends AnimatedComponent { class Dismissable extends AnimatedComponent {
Dismissable({ Dismissable({
String key, Key key,
this.child, this.child,
this.onDismissed this.onDismissed
// TODO(hansmuller): direction // TODO(hansmuller): direction
......
...@@ -46,7 +46,7 @@ typedef void DrawerStatusChangedCallback(DrawerStatus status); ...@@ -46,7 +46,7 @@ typedef void DrawerStatusChangedCallback(DrawerStatus status);
class Drawer extends AnimatedComponent { class Drawer extends AnimatedComponent {
Drawer({ Drawer({
String key, Key key,
this.children, this.children,
this.showing: false, this.showing: false,
this.level: 0, this.level: 0,
...@@ -143,7 +143,8 @@ class Drawer extends AnimatedComponent { ...@@ -143,7 +143,8 @@ class Drawer extends AnimatedComponent {
if (_lastStatus != null && status != _lastStatus) { if (_lastStatus != null && status != _lastStatus) {
if (status == DrawerStatus.inactive && if (status == DrawerStatus.inactive &&
navigator != null && navigator != null &&
navigator.currentRoute.key == this) navigator.currentRoute is RouteState &&
(navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
navigator.pop(); navigator.pop();
if (onStatusChanged != null) if (onStatusChanged != null)
onStatusChanged(status); onStatusChanged(status);
......
...@@ -6,7 +6,7 @@ import 'package:sky/widgets/basic.dart'; ...@@ -6,7 +6,7 @@ import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/theme.dart';
class DrawerDivider extends Component { class DrawerDivider extends Component {
DrawerDivider({ String key }) : super(key: key); DrawerDivider({ Key key }) : super(key: key);
Widget build() { Widget build() {
return new Container( return new Container(
......
...@@ -12,7 +12,7 @@ import 'package:sky/widgets/theme.dart'; ...@@ -12,7 +12,7 @@ import 'package:sky/widgets/theme.dart';
class DrawerHeader extends Component { class DrawerHeader extends Component {
DrawerHeader({ String key, this.children }) : super(key: key); DrawerHeader({ Key key, this.children }) : super(key: key);
final List<Widget> children; final List<Widget> children;
......
...@@ -15,7 +15,7 @@ import 'package:sky/widgets/theme.dart'; ...@@ -15,7 +15,7 @@ import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/widget.dart'; import 'package:sky/widgets/widget.dart';
class DrawerItem extends ButtonBase { class DrawerItem extends ButtonBase {
DrawerItem({ String key, this.icon, this.children, this.onPressed, this.selected: false }) DrawerItem({ Key key, this.icon, this.children, this.onPressed, this.selected: false })
: super(key: key); : super(key: key);
String icon; String icon;
......
...@@ -10,7 +10,7 @@ import 'package:sky/widgets/scrollable.dart'; ...@@ -10,7 +10,7 @@ import 'package:sky/widgets/scrollable.dart';
abstract class FixedHeightScrollable extends Scrollable { abstract class FixedHeightScrollable extends Scrollable {
FixedHeightScrollable({ String key, this.itemHeight, this.padding }) FixedHeightScrollable({ Key key, this.itemHeight, this.padding })
: super(key: key) { : super(key: key) {
assert(itemHeight != null); assert(itemHeight != null);
} }
......
...@@ -9,7 +9,7 @@ import 'package:sky/widgets/theme.dart'; ...@@ -9,7 +9,7 @@ import 'package:sky/widgets/theme.dart';
class FlatButton extends MaterialButton { class FlatButton extends MaterialButton {
FlatButton({ FlatButton({
String key, Key key,
Widget child, Widget child,
bool enabled: true, bool enabled: true,
Function onPressed Function onPressed
......
...@@ -16,7 +16,7 @@ const double _kSize = 56.0; ...@@ -16,7 +16,7 @@ const double _kSize = 56.0;
class FloatingActionButton extends ButtonBase { class FloatingActionButton extends ButtonBase {
FloatingActionButton({ FloatingActionButton({
String key, Key key,
this.child, this.child,
this.backgroundColor, this.backgroundColor,
this.onPressed this.onPressed
......
...@@ -19,7 +19,7 @@ class IconThemeData { ...@@ -19,7 +19,7 @@ class IconThemeData {
class IconTheme extends Inherited { class IconTheme extends Inherited {
IconTheme({ IconTheme({
String key, Key key,
this.data, this.data,
Widget child Widget child
}) : super(key: key, child: child) { }) : super(key: key, child: child) {
...@@ -49,7 +49,7 @@ final AssetBundle _iconBundle = _initIconBundle(); ...@@ -49,7 +49,7 @@ final AssetBundle _iconBundle = _initIconBundle();
class Icon extends Component { class Icon extends Component {
Icon({ Icon({
String key, Key key,
this.size, this.size,
this.type: '', this.type: '',
this.color, this.color,
......
...@@ -11,8 +11,7 @@ import 'package:sky/widgets/widget.dart'; ...@@ -11,8 +11,7 @@ import 'package:sky/widgets/widget.dart';
class IconButton extends Component { class IconButton extends Component {
IconButton({ String icon: '', this.onPressed, this.color }) IconButton({ Key key, this.icon, this.onPressed, this.color }) : super(key: key);
: super(key: icon), icon = icon;
final String icon; final String icon;
final Function onPressed; final Function onPressed;
......
...@@ -126,7 +126,7 @@ class RenderInkWell extends RenderProxyBox { ...@@ -126,7 +126,7 @@ class RenderInkWell extends RenderProxyBox {
} }
class InkWell extends OneChildRenderObjectWrapper { class InkWell extends OneChildRenderObjectWrapper {
InkWell({ String key, Widget child }) InkWell({ Key key, Widget child })
: super(key: key, child: child); : super(key: key, child: child);
RenderInkWell get root => super.root; RenderInkWell get root => super.root;
......
...@@ -20,7 +20,7 @@ const Map<MaterialType, double> edges = const { ...@@ -20,7 +20,7 @@ const Map<MaterialType, double> edges = const {
class Material extends Component { class Material extends Component {
Material({ Material({
String key, Key key,
this.child, this.child,
this.type: MaterialType.card, this.type: MaterialType.card,
this.level: 0, this.level: 0,
...@@ -49,7 +49,7 @@ class Material extends Component { ...@@ -49,7 +49,7 @@ class Material extends Component {
Widget build() { Widget build() {
return new AnimatedContainer( return new AnimatedContainer(
duration: const Duration(milliseconds: 1000), duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundColor: _backgroundColor, backgroundColor: _backgroundColor,
borderRadius: edges[type], borderRadius: edges[type],
......
...@@ -11,7 +11,7 @@ import 'package:sky/widgets/material.dart'; ...@@ -11,7 +11,7 @@ import 'package:sky/widgets/material.dart';
abstract class MaterialButton extends ButtonBase { abstract class MaterialButton extends ButtonBase {
MaterialButton({ MaterialButton({
String key, Key key,
this.child, this.child,
this.enabled: true, this.enabled: true,
this.onPressed this.onPressed
......
...@@ -7,7 +7,7 @@ import 'package:sky/widgets/widget.dart'; ...@@ -7,7 +7,7 @@ import 'package:sky/widgets/widget.dart';
class ModalOverlay extends Component { class ModalOverlay extends Component {
ModalOverlay({ String key, this.children, this.onDismiss }) : super(key: key); ModalOverlay({ Key key, this.children, this.onDismiss }) : super(key: key);
final List<Widget> children; final List<Widget> children;
final Function onDismiss; final Function onDismiss;
......
...@@ -12,25 +12,24 @@ import 'package:vector_math/vector_math.dart'; ...@@ -12,25 +12,24 @@ import 'package:vector_math/vector_math.dart';
typedef Widget Builder(Navigator navigator, RouteBase route); typedef Widget Builder(Navigator navigator, RouteBase route);
abstract class RouteBase { abstract class RouteBase {
RouteBase({ this.key });
final Object key;
Widget build(Navigator navigator, RouteBase route); Widget build(Navigator navigator, RouteBase route);
void popState() { } void popState() { }
} }
class Route extends RouteBase { class Route extends RouteBase {
Route({ String name, this.builder }) : super(key: name); Route({ this.name, this.builder });
String get name => key; final String name;
final Builder builder; final Builder builder;
Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
} }
class RouteState extends RouteBase { class RouteState extends RouteBase {
RouteState({ this.callback, this.route, Object key }) : super(key: key); RouteState({ this.callback, this.route, this.owner });
RouteBase route;
Function callback; Function callback;
RouteBase route;
StatefulComponent owner;
Widget build(Navigator navigator, RouteBase route) => null; Widget build(Navigator navigator, RouteBase route) => null;
...@@ -47,7 +46,7 @@ const Point _kTransitionStartPoint = const Point(0.0, 75.0); ...@@ -47,7 +46,7 @@ const Point _kTransitionStartPoint = const Point(0.0, 75.0);
enum TransitionDirection { forward, reverse } enum TransitionDirection { forward, reverse }
class Transition extends AnimatedComponent { class Transition extends AnimatedComponent {
Transition({ Transition({
String key, Key key,
this.content, this.content,
this.direction, this.direction,
this.onDismissed, this.onDismissed,
...@@ -144,9 +143,8 @@ class Transition extends AnimatedComponent { ...@@ -144,9 +143,8 @@ class Transition extends AnimatedComponent {
} }
class HistoryEntry { class HistoryEntry {
HistoryEntry({ this.route, this.key }); HistoryEntry({ this.route });
final RouteBase route; final RouteBase route;
final int key;
bool transitionFinished = false; bool transitionFinished = false;
// TODO(jackson): Keep track of the requested transition // TODO(jackson): Keep track of the requested transition
} }
...@@ -158,12 +156,11 @@ class NavigationState { ...@@ -158,12 +156,11 @@ class NavigationState {
if (route.name != null) if (route.name != null)
namedRoutes[route.name] = route; namedRoutes[route.name] = route;
} }
history.add(new HistoryEntry(route: routes[0], key: _lastKey++)); history.add(new HistoryEntry(route: routes[0]));
} }
List<HistoryEntry> history = new List<HistoryEntry>(); List<HistoryEntry> history = new List<HistoryEntry>();
int historyIndex = 0; int historyIndex = 0;
int _lastKey = 0;
Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>(); Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>();
RouteBase get currentRoute => history[historyIndex].route; RouteBase get currentRoute => history[historyIndex].route;
...@@ -176,7 +173,7 @@ class NavigationState { ...@@ -176,7 +173,7 @@ class NavigationState {
} }
void push(RouteBase route) { void push(RouteBase route) {
HistoryEntry historyEntry = new HistoryEntry(route: route, key: _lastKey++); HistoryEntry historyEntry = new HistoryEntry(route: route);
history.insert(historyIndex + 1, historyEntry); history.insert(historyIndex + 1, historyEntry);
historyIndex++; historyIndex++;
} }
...@@ -193,7 +190,7 @@ class NavigationState { ...@@ -193,7 +190,7 @@ class NavigationState {
class Navigator extends StatefulComponent { class Navigator extends StatefulComponent {
Navigator(this.state, { String key }) : super(key: key); Navigator(this.state, { Key key }) : super(key: key);
NavigationState state; NavigationState state;
...@@ -203,9 +200,9 @@ class Navigator extends StatefulComponent { ...@@ -203,9 +200,9 @@ class Navigator extends StatefulComponent {
RouteBase get currentRoute => state.currentRoute; RouteBase get currentRoute => state.currentRoute;
void pushState(Object key, Function callback) { void pushState(StatefulComponent owner, Function callback) {
RouteBase route = new RouteState( RouteBase route = new RouteState(
key: key, owner: owner,
callback: callback, callback: callback,
route: state.currentRoute route: state.currentRoute
); );
...@@ -245,7 +242,7 @@ class Navigator extends StatefulComponent { ...@@ -245,7 +242,7 @@ class Navigator extends StatefulComponent {
if (content == null) if (content == null)
continue; continue;
Transition transition = new Transition( Transition transition = new Transition(
key: historyEntry.key.toString(), key: new Key.fromObjectIdentity(historyEntry),
content: content, content: content,
direction: (i <= state.historyIndex) ? TransitionDirection.forward : TransitionDirection.reverse, direction: (i <= state.historyIndex) ? TransitionDirection.forward : TransitionDirection.reverse,
interactive: (i == state.historyIndex), interactive: (i == state.historyIndex),
......
...@@ -35,7 +35,7 @@ typedef void PopupMenuStatusChangedCallback(PopupMenuStatus status); ...@@ -35,7 +35,7 @@ typedef void PopupMenuStatusChangedCallback(PopupMenuStatus status);
class PopupMenu extends AnimatedComponent { class PopupMenu extends AnimatedComponent {
PopupMenu({ PopupMenu({
String key, Key key,
this.showing, this.showing,
this.onStatusChanged, this.onStatusChanged,
this.items, this.items,
...@@ -123,7 +123,8 @@ class PopupMenu extends AnimatedComponent { ...@@ -123,7 +123,8 @@ class PopupMenu extends AnimatedComponent {
if (_lastStatus != null && status != _lastStatus) { if (_lastStatus != null && status != _lastStatus) {
if (status == PopupMenuStatus.inactive && if (status == PopupMenuStatus.inactive &&
navigator != null && navigator != null &&
navigator.currentRoute.key == this) navigator.currentRoute is RouteState &&
(navigator.currentRoute as RouteState).owner == this) // TODO(ianh): remove cast once analyzer is cleverer
navigator.pop(); navigator.pop();
if (onStatusChanged != null) if (onStatusChanged != null)
onStatusChanged(status); onStatusChanged(status);
......
...@@ -13,7 +13,7 @@ const double kBaselineOffsetFromBottom = 20.0; ...@@ -13,7 +13,7 @@ const double kBaselineOffsetFromBottom = 20.0;
class PopupMenuItem extends Component { class PopupMenuItem extends Component {
PopupMenuItem({ PopupMenuItem({
String key, Key key,
this.onPressed, this.onPressed,
this.child this.child
}) : super(key: key); }) : super(key: key);
......
...@@ -17,7 +17,7 @@ typedef void ValueChanged(value); ...@@ -17,7 +17,7 @@ typedef void ValueChanged(value);
class Radio extends ButtonBase { class Radio extends ButtonBase {
Radio({ Radio({
String key, Key key,
this.value, this.value,
this.groupValue, this.groupValue,
this.onChanged this.onChanged
......
...@@ -10,7 +10,7 @@ import 'package:sky/widgets/theme.dart'; ...@@ -10,7 +10,7 @@ import 'package:sky/widgets/theme.dart';
class RaisedButton extends MaterialButton { class RaisedButton extends MaterialButton {
RaisedButton({ RaisedButton({
String key, Key key,
Widget child, Widget child,
bool enabled: true, bool enabled: true,
Function onPressed Function onPressed
......
...@@ -173,7 +173,7 @@ class RenderScaffold extends RenderBox { ...@@ -173,7 +173,7 @@ class RenderScaffold extends RenderBox {
class Scaffold extends RenderObjectWrapper { class Scaffold extends RenderObjectWrapper {
Scaffold({ Scaffold({
String key, Key key,
Widget body, Widget body,
Widget statusBar, Widget statusBar,
Widget toolbar, Widget toolbar,
......
...@@ -27,7 +27,7 @@ enum ScrollDirection { vertical, horizontal } ...@@ -27,7 +27,7 @@ enum ScrollDirection { vertical, horizontal }
abstract class Scrollable extends StatefulComponent { abstract class Scrollable extends StatefulComponent {
Scrollable({ Scrollable({
String key, Key key,
this.direction: ScrollDirection.vertical this.direction: ScrollDirection.vertical
}) : super(key: key); }) : super(key: key);
......
...@@ -11,7 +11,7 @@ typedef Widget ItemBuilder<T>(T item); ...@@ -11,7 +11,7 @@ typedef Widget ItemBuilder<T>(T item);
class ScrollableList<T> extends FixedHeightScrollable { class ScrollableList<T> extends FixedHeightScrollable {
ScrollableList({ ScrollableList({
String key, Key key,
this.items, this.items,
this.itemBuilder, this.itemBuilder,
double itemHeight, double itemHeight,
......
...@@ -8,7 +8,7 @@ import 'package:sky/widgets/scrollable.dart'; ...@@ -8,7 +8,7 @@ import 'package:sky/widgets/scrollable.dart';
class ScrollableViewport extends Scrollable { class ScrollableViewport extends Scrollable {
ScrollableViewport({ String key, this.child }) : super(key: key); ScrollableViewport({ Key key, this.child }) : super(key: key);
Widget child; Widget child;
...@@ -54,7 +54,7 @@ class ScrollableViewport extends Scrollable { ...@@ -54,7 +54,7 @@ class ScrollableViewport extends Scrollable {
class ScrollableBlock extends Component { class ScrollableBlock extends Component {
ScrollableBlock(this.children, { String key }) : super(key: key); ScrollableBlock(this.children, { Key key }) : super(key: key);
final List<Widget> children; final List<Widget> children;
......
...@@ -2,15 +2,29 @@ ...@@ -2,15 +2,29 @@
// 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:sky/animation/animated_value.dart';
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/painting/text_style.dart'; import 'package:sky/painting/text_style.dart';
import 'package:sky/theme/typography.dart' as typography; import 'package:sky/theme/typography.dart' as typography;
import 'package:sky/widgets/animated_component.dart';
import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart'; import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/theme.dart'; import 'package:sky/widgets/theme.dart';
import 'package:vector_math/vector_math.dart';
enum SnackBarStatus {
active,
inactive,
}
typedef void SnackBarStatusChangedCallback(SnackBarStatus status);
const Duration _kSlideInDuration = const Duration(milliseconds: 200);
class SnackBarAction extends Component { class SnackBarAction extends Component {
SnackBarAction({String key, this.label, this.onPressed }) : super(key: key) { SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
assert(label != null); assert(label != null);
} }
...@@ -29,18 +43,64 @@ class SnackBarAction extends Component { ...@@ -29,18 +43,64 @@ class SnackBarAction extends Component {
} }
} }
class SnackBar extends Component { class SnackBar extends AnimatedComponent {
SnackBar({ SnackBar({
String key, Key key,
this.content, this.content,
this.actions this.actions,
this.showing,
this.onStatusChanged
}) : super(key: key) { }) : super(key: key) {
assert(content != null); assert(content != null);
} }
final Widget content; Widget content;
final List<SnackBarAction> actions; List<SnackBarAction> actions;
bool showing;
SnackBarStatusChangedCallback onStatusChanged;
void syncFields(SnackBar source) {
content = source.content;
actions = source.actions;
onStatusChanged = source.onStatusChanged;
if (showing != source.showing) {
showing = source.showing;
showing ? _show() : _hide();
}
}
AnimatedValue<Point> _position;
AnimationPerformance _performance;
void initState() {
_position = new AnimatedValue<Point>(new Point(0.0, 50.0), end: Point.origin);
_performance = new AnimationPerformance()
..duration = _kSlideInDuration
..variable = _position
..addListener(_checkStatusChanged);
watch(_performance);
if (showing)
_show();
}
void _show() {
_performance.play();
}
void _hide() {
_performance.reverse();
}
SnackBarStatus _lastStatus;
void _checkStatusChanged() {
SnackBarStatus status = _status;
if (_lastStatus != null && status != _lastStatus && onStatusChanged != null)
onStatusChanged(status);
_lastStatus = status;
}
SnackBarStatus get _status => _performance.isDismissed ? SnackBarStatus.inactive : SnackBarStatus.active;
Widget build() { Widget build() {
List<Widget> children = [ List<Widget> children = [
...@@ -53,10 +113,13 @@ class SnackBar extends Component { ...@@ -53,10 +113,13 @@ class SnackBar extends Component {
) )
) )
) )
]; ]..addAll(actions);
if (actions != null)
children.addAll(actions); Matrix4 transform = new Matrix4.identity();
return new Material( transform.translate(_position.value.x, _position.value.y);
return new Transform(
transform: transform,
child: new Material(
level: 2, level: 2,
color: const Color(0xFF323232), color: const Color(0xFF323232),
type: MaterialType.canvas, type: MaterialType.canvas,
...@@ -67,6 +130,7 @@ class SnackBar extends Component { ...@@ -67,6 +130,7 @@ class SnackBar extends Component {
child: new Flex(children) child: new Flex(children)
) )
) )
)
); );
} }
} }
...@@ -26,7 +26,7 @@ class Switch extends Toggleable { ...@@ -26,7 +26,7 @@ class Switch extends Toggleable {
// TODO(jackson): Hit-test the switch so that it can respond to both taps and swipe gestures // TODO(jackson): Hit-test the switch so that it can respond to both taps and swipe gestures
Switch({ Switch({
String key, Key key,
bool value, bool value,
ValueChanged onChanged ValueChanged onChanged
}) : super(key: key, value: value, onChanged: onChanged); }) : super(key: key, value: value, onChanged: onChanged);
......
...@@ -249,14 +249,14 @@ class RenderTabBar extends RenderBox with ...@@ -249,14 +249,14 @@ class RenderTabBar extends RenderBox with
class TabBarWrapper extends MultiChildRenderObjectWrapper { class TabBarWrapper extends MultiChildRenderObjectWrapper {
TabBarWrapper({ TabBarWrapper({
Key key,
List<Widget> children, List<Widget> children,
this.selectedIndex, this.selectedIndex,
this.backgroundColor, this.backgroundColor,
this.indicatorColor, this.indicatorColor,
this.textAndIcons, this.textAndIcons,
this.scrollable: false, this.scrollable: false,
this.onLayoutChanged, this.onLayoutChanged
String key
}) : super(key: key, children: children); }) : super(key: key, children: children);
final int selectedIndex; final int selectedIndex;
...@@ -289,7 +289,7 @@ class TabLabel { ...@@ -289,7 +289,7 @@ class TabLabel {
class Tab extends Component { class Tab extends Component {
Tab({ Tab({
String key, Key key,
this.label, this.label,
this.selected: false this.selected: false
}) : super(key: key) { }) : super(key: key) {
...@@ -347,7 +347,7 @@ class Tab extends Component { ...@@ -347,7 +347,7 @@ class Tab extends Component {
class TabBar extends Scrollable { class TabBar extends Scrollable {
TabBar({ TabBar({
String key, Key key,
this.labels, this.labels,
this.selectedIndex: 0, this.selectedIndex: 0,
this.onChanged, this.onChanged,
...@@ -378,13 +378,11 @@ class TabBar extends Scrollable { ...@@ -378,13 +378,11 @@ class TabBar extends Scrollable {
} }
Widget _toTab(TabLabel label, int tabIndex) { Widget _toTab(TabLabel label, int tabIndex) {
Tab tab = new Tab(
label: label,
selected: tabIndex == selectedIndex,
key: label.text == null ? label.icon : label.text
);
return new Listener( return new Listener(
child: tab, child: new Tab(
label: label,
selected: tabIndex == selectedIndex
),
onGestureTap: (_) => _handleTap(tabIndex) onGestureTap: (_) => _handleTap(tabIndex)
); );
} }
...@@ -472,7 +470,7 @@ class TabNavigatorView { ...@@ -472,7 +470,7 @@ class TabNavigatorView {
class TabNavigator extends Component { class TabNavigator extends Component {
TabNavigator({ TabNavigator({
String key, Key key,
this.views, this.views,
this.selectedIndex: 0, this.selectedIndex: 0,
this.onChanged, this.onChanged,
......
...@@ -11,7 +11,7 @@ export 'package:sky/theme/theme_data.dart' show ThemeData, ThemeBrightness; ...@@ -11,7 +11,7 @@ export 'package:sky/theme/theme_data.dart' show ThemeData, ThemeBrightness;
class Theme extends Inherited { class Theme extends Inherited {
Theme({ Theme({
String key, Key key,
this.data, this.data,
Widget child Widget child
}) : super(key: key, child: child) { }) : super(key: key, child: child) {
......
...@@ -17,7 +17,7 @@ const Duration _kCheckDuration = const Duration(milliseconds: 200); ...@@ -17,7 +17,7 @@ const Duration _kCheckDuration = const Duration(milliseconds: 200);
abstract class Toggleable extends AnimatedComponent { abstract class Toggleable extends AnimatedComponent {
Toggleable({ Toggleable({
String key, Key key,
this.value, this.value,
this.onChanged this.onChanged
}) : super(key: key); }) : super(key: key);
......
...@@ -16,7 +16,7 @@ import 'package:sky/widgets/icon.dart'; ...@@ -16,7 +16,7 @@ import 'package:sky/widgets/icon.dart';
class ToolBar extends Component { class ToolBar extends Component {
ToolBar({ ToolBar({
String key, Key key,
this.left, this.left,
this.center, this.center,
this.right, this.right,
......
...@@ -8,9 +8,11 @@ import 'package:sky/widgets/block_viewport.dart'; ...@@ -8,9 +8,11 @@ import 'package:sky/widgets/block_viewport.dart';
import 'package:sky/widgets/scrollable.dart'; import 'package:sky/widgets/scrollable.dart';
import 'package:sky/widgets/widget.dart'; import 'package:sky/widgets/widget.dart';
export 'package:sky/widgets/block_viewport.dart' show BlockViewportLayoutState;
class VariableHeightScrollable extends Scrollable { class VariableHeightScrollable extends Scrollable {
VariableHeightScrollable({ VariableHeightScrollable({
String key, Key key,
this.builder, this.builder,
this.token, this.token,
this.layoutState this.layoutState
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'dart:sky' as sky; import 'dart:sky' as sky;
import 'package:sky/base/debug.dart';
import 'package:sky/base/hit_test.dart'; import 'package:sky/base/hit_test.dart';
import 'package:sky/mojo/activity.dart' as activity; import 'package:sky/mojo/activity.dart' as activity;
import 'package:sky/rendering/box.dart'; import 'package:sky/rendering/box.dart';
...@@ -22,22 +21,54 @@ final bool _shouldLogRenderDuration = false; ...@@ -22,22 +21,54 @@ final bool _shouldLogRenderDuration = false;
typedef Widget Builder(); typedef Widget Builder();
typedef void WidgetTreeWalker(Widget); typedef void WidgetTreeWalker(Widget);
abstract class KeyBase {
}
abstract class Key extends KeyBase {
Key.constructor(); // so that subclasses can call us, since the Key() factory constructor shadows the implicit constructor
factory Key(String value) => new StringKey(value);
factory Key.stringify(Object value) => new StringKey(value.toString());
factory Key.fromObjectIdentity(Object value) => new ObjectKey(value);
factory Key.unique() => new UniqueKey();
}
class StringKey extends Key {
StringKey(this.value) : super.constructor();
final String value;
String toString() => value;
bool operator==(other) => other is StringKey && other.value == value;
int get hashCode => value.hashCode;
}
class ObjectKey extends Key {
ObjectKey(this.value) : super.constructor();
final Object value;
String toString() => '[Instance of ${value.runtimeType}]';
bool operator==(other) => other is ObjectKey && identical(other.value, value);
int get hashCode => identityHashCode(value);
}
class UniqueKey extends Key {
UniqueKey() : super.constructor();
String toString() => '[$hashCode]';
}
/// A base class for elements of the widget tree /// A base class for elements of the widget tree
abstract class Widget { abstract class Widget {
Widget({ String key }) : _key = key { Widget({ Key key }) : _key = key {
assert(_isConstructedDuringBuild()); assert(_isConstructedDuringBuild());
} }
// TODO(jackson): Remove this workaround for limitation of Dart mixins // TODO(jackson): Remove this workaround for limitation of Dart mixins
Widget._withKey(String key) : _key = key { Widget._withKey(Key key) : _key = key {
assert(_isConstructedDuringBuild()); assert(_isConstructedDuringBuild());
} }
// you should not build the UI tree ahead of time, build it only during build() // you should not build the UI tree ahead of time, build it only during build()
bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents || _inLayoutCallbackBuilder > 0; bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents || _inLayoutCallbackBuilder > 0;
String _key; Key _key;
/// A semantic identifer for this widget /// A semantic identifer for this widget
/// ///
...@@ -47,7 +78,7 @@ abstract class Widget { ...@@ -47,7 +78,7 @@ abstract class Widget {
/// Assigning a key to a widget can improve performance by causing the /// Assigning a key to a widget can improve performance by causing the
/// framework to sync widgets that share a lot of common structure and can /// framework to sync widgets that share a lot of common structure and can
/// help match stateful components semantically rather than positionally. /// help match stateful components semantically rather than positionally.
String get key => _key; Key get key => _key;
Widget _parent; Widget _parent;
...@@ -244,11 +275,11 @@ abstract class Widget { ...@@ -244,11 +275,11 @@ abstract class Widget {
// stylistic information, etc. // stylistic information, etc.
abstract class TagNode extends Widget { abstract class TagNode extends Widget {
TagNode(Widget child, { String key }) TagNode(Widget child, { Key key })
: this.child = child, super(key: key); : this.child = child, super(key: key);
// TODO(jackson): Remove this workaround for limitation of Dart mixins // TODO(jackson): Remove this workaround for limitation of Dart mixins
TagNode._withKey(Widget child, String key) TagNode._withKey(Widget child, Key key)
: this.child = child, super._withKey(key); : this.child = child, super._withKey(key);
Widget child; Widget child;
...@@ -285,14 +316,14 @@ abstract class TagNode extends Widget { ...@@ -285,14 +316,14 @@ abstract class TagNode extends Widget {
} }
class ParentDataNode extends TagNode { class ParentDataNode extends TagNode {
ParentDataNode(Widget child, this.parentData, { String key }) ParentDataNode(Widget child, this.parentData, { Key key })
: super(child, key: key); : super(child, key: key);
final ParentData parentData; final ParentData parentData;
} }
abstract class Inherited extends TagNode { abstract class Inherited extends TagNode {
Inherited({ String key, Widget child }) : super._withKey(child, key); Inherited({ Key key, Widget child }) : super._withKey(child, key);
void _sync(Widget old, dynamic slot) { void _sync(Widget old, dynamic slot) {
if (old != null && syncShouldNotify(old)) { if (old != null && syncShouldNotify(old)) {
...@@ -321,7 +352,7 @@ typedef void EventListener(sky.Event e); ...@@ -321,7 +352,7 @@ typedef void EventListener(sky.Event e);
class Listener extends TagNode { class Listener extends TagNode {
Listener({ Listener({
String key, Key key,
Widget child, Widget child,
EventListener onWheel, EventListener onWheel,
GestureEventListener onGestureFlingCancel, GestureEventListener onGestureFlingCancel,
...@@ -408,7 +439,7 @@ class Listener extends TagNode { ...@@ -408,7 +439,7 @@ class Listener extends TagNode {
abstract class Component extends Widget { abstract class Component extends Widget {
Component({ String key }) Component({ Key key })
: _order = _currentOrder + 1, : _order = _currentOrder + 1,
super._withKey(key); super._withKey(key);
...@@ -525,7 +556,7 @@ abstract class Component extends Widget { ...@@ -525,7 +556,7 @@ abstract class Component extends Widget {
abstract class StatefulComponent extends Component { abstract class StatefulComponent extends Component {
StatefulComponent({ String key }) : super(key: key); StatefulComponent({ Key key }) : super(key: key);
bool _disqualifiedFromEverAppearingAgain = false; bool _disqualifiedFromEverAppearingAgain = false;
bool _isStateInitialized = false; bool _isStateInitialized = false;
...@@ -586,7 +617,7 @@ abstract class StatefulComponent extends Component { ...@@ -586,7 +617,7 @@ abstract class StatefulComponent extends Component {
return super.syncChild(node, oldNode, slot); return super.syncChild(node, oldNode, slot);
} }
void setState(Function fn()) { void setState(void fn()) {
assert(!_disqualifiedFromEverAppearingAgain); assert(!_disqualifiedFromEverAppearingAgain);
fn(); fn();
scheduleBuild(); scheduleBuild();
...@@ -600,17 +631,22 @@ int _inLayoutCallbackBuilder = 0; ...@@ -600,17 +631,22 @@ int _inLayoutCallbackBuilder = 0;
class LayoutCallbackBuilderHandle { bool _active = true; } class LayoutCallbackBuilderHandle { bool _active = true; }
LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() { LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() {
if (!inDebugBuild) LayoutCallbackBuilderHandle result;
return null; assert(() {
_inLayoutCallbackBuilder += 1; _inLayoutCallbackBuilder += 1;
return new LayoutCallbackBuilderHandle(); result = new LayoutCallbackBuilderHandle();
return true;
});
return result;
} }
void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) { void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) {
if (!inDebugBuild) assert(() {
return;
assert(handle._active); assert(handle._active);
handle._active = false; handle._active = false;
_inLayoutCallbackBuilder -= 1; _inLayoutCallbackBuilder -= 1;
return true;
});
Widget._notifyMountStatusChanged();
} }
List<int> _debugFrameTimes = <int>[]; List<int> _debugFrameTimes = <int>[];
...@@ -680,7 +716,7 @@ void _scheduleComponentForRender(Component c) { ...@@ -680,7 +716,7 @@ void _scheduleComponentForRender(Component c) {
// become stateful. // become stateful.
abstract class RenderObjectWrapper extends Widget { abstract class RenderObjectWrapper extends Widget {
RenderObjectWrapper({ String key }) : super(key: key); RenderObjectWrapper({ Key key }) : super(key: key);
RenderObject createNode(); RenderObject createNode();
...@@ -764,7 +800,7 @@ abstract class RenderObjectWrapper extends Widget { ...@@ -764,7 +800,7 @@ abstract class RenderObjectWrapper extends Widget {
abstract class LeafRenderObjectWrapper extends RenderObjectWrapper { abstract class LeafRenderObjectWrapper extends RenderObjectWrapper {
LeafRenderObjectWrapper({ String key }) : super(key: key); LeafRenderObjectWrapper({ Key key }) : super(key: key);
void insertChildRoot(RenderObjectWrapper child, dynamic slot) { void insertChildRoot(RenderObjectWrapper child, dynamic slot) {
assert(false); assert(false);
...@@ -778,7 +814,7 @@ abstract class LeafRenderObjectWrapper extends RenderObjectWrapper { ...@@ -778,7 +814,7 @@ abstract class LeafRenderObjectWrapper extends RenderObjectWrapper {
abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
OneChildRenderObjectWrapper({ String key, Widget child }) OneChildRenderObjectWrapper({ Key key, Widget child })
: _child = child, super(key: key); : _child = child, super(key: key);
Widget _child; Widget _child;
...@@ -826,7 +862,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { ...@@ -826,7 +862,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
// In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes
// to use as the "insert before" sibling in ContainerRenderObjectMixin.add() calls // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() calls
MultiChildRenderObjectWrapper({ String key, List<Widget> children }) MultiChildRenderObjectWrapper({ Key key, List<Widget> children })
: this.children = children == null ? const [] : children, : this.children = children == null ? const [] : children,
super(key: key) { super(key: key) {
assert(!_debugHasDuplicateIds()); assert(!_debugHasDuplicateIds());
...@@ -865,7 +901,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { ...@@ -865,7 +901,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
} }
bool _debugHasDuplicateIds() { bool _debugHasDuplicateIds() {
var idSet = new HashSet<String>(); var idSet = new HashSet<Key>();
for (var child in children) { for (var child in children) {
assert(child != null); assert(child != null);
if (child.key == null) if (child.key == null)
...@@ -920,9 +956,9 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { ...@@ -920,9 +956,9 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
nextSibling = children[endIndex].root; nextSibling = children[endIndex].root;
} }
HashMap<String, Widget> oldNodeIdMap = null; HashMap<Key, Widget> oldNodeIdMap = null;
bool oldNodeReordered(String key) { bool oldNodeReordered(Key key) {
return oldNodeIdMap != null && return oldNodeIdMap != null &&
oldNodeIdMap.containsKey(key) && oldNodeIdMap.containsKey(key) &&
oldNodeIdMap[key] == null; oldNodeIdMap[key] == null;
...@@ -940,7 +976,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { ...@@ -940,7 +976,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
if (oldNodeIdMap != null) if (oldNodeIdMap != null)
return; return;
oldNodeIdMap = new HashMap<String, Widget>(); oldNodeIdMap = new HashMap<Key, Widget>();
for (int i = oldStartIndex; i < oldEndIndex; i++) { for (int i = oldStartIndex; i < oldEndIndex; i++) {
var node = oldChildren[i]; var node = oldChildren[i];
if (node.key != null) if (node.key != null)
...@@ -1045,7 +1081,7 @@ class WidgetSkyBinding extends SkyBinding { ...@@ -1045,7 +1081,7 @@ class WidgetSkyBinding extends SkyBinding {
abstract class App extends StatefulComponent { abstract class App extends StatefulComponent {
App({ String key }) : super(key: key); App({ Key key }) : super(key: key);
void _handleEvent(sky.Event event) { void _handleEvent(sky.Event event) {
if (event.type == 'back') if (event.type == 'back')
...@@ -1093,7 +1129,7 @@ abstract class AbstractWidgetRoot extends StatefulComponent { ...@@ -1093,7 +1129,7 @@ abstract class AbstractWidgetRoot extends StatefulComponent {
} }
class RenderViewWrapper extends OneChildRenderObjectWrapper { class RenderViewWrapper extends OneChildRenderObjectWrapper {
RenderViewWrapper({ String key, Widget child }) : super(key: key, child: child); RenderViewWrapper({ Key key, Widget child }) : super(key: key, child: child);
RenderView get root => super.root; RenderView get root => super.root;
RenderView createNode() => SkyBinding.instance.renderView; RenderView createNode() => SkyBinding.instance.renderView;
} }
......
...@@ -11,4 +11,4 @@ environment: ...@@ -11,4 +11,4 @@ environment:
sdk: '>=1.8.0 <2.0.0' sdk: '>=1.8.0 <2.0.0'
homepage: https://github.com/domokit/mojo/tree/master/sky homepage: https://github.com/domokit/mojo/tree/master/sky
name: sky name: sky
version: 0.0.19 version: 0.0.21
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