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