Commit 35b5ecf8 authored by Viktor Lidholt's avatar Viktor Lidholt

Merge branch 'master' of github.com:domokit/sky_engine

parents 34e1268f eced8b3c
......@@ -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",
......
......@@ -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;
......
// 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:sky/widgets/basic.dart';
import 'package:sky/widgets/card.dart';
import 'package:sky/widgets/dismissable.dart';
typedef void FitnessItemHandler(FitnessItem item);
const double kFitnessItemHeight = 79.0;
class FitnessItem {
FitnessItem({ this.when }) {
assert(when != null);
}
final DateTime when;
// TODO(jackson): Internationalize
String get displayDate => "${when.year.toString()}-${when.month.toString().padLeft(2,'0')}-${when.day.toString().padLeft(2,'0')}";
}
abstract class FitnessItemRow extends Component {
FitnessItemRow({ FitnessItem item, this.onDismissed })
: this.item = item,
super(key: new Key(item.when.toString()));
final FitnessItem item;
final FitnessItemHandler onDismissed;
Widget buildContent();
Widget build() {
return new Dismissable(
onDismissed: () => onDismissed(item),
child: new Card(
child: new Container(
height: kFitnessItemHeight,
padding: const EdgeDims.all(8.0),
child: buildContent()
)
)
);
}
}
......@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
enum FitnessMode { measure, run }
enum FitnessMode { feed, chart }
enum BackupMode { enabled, disabled }
......@@ -9,31 +9,44 @@ import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/task_description.dart';
import 'meal.dart';
import 'measurement.dart';
import 'home.dart';
import 'feed.dart';
import 'settings.dart';
import 'fitness_item.dart';
import 'fitness_types.dart';
class FitnessApp extends App {
NavigationState _navigationState;
final List<FitnessItem> _userData = [
new Measurement(weight: 180.0, when: new DateTime.now().add(const Duration(days: -1))),
new Measurement(weight: 160.0, when: new DateTime.now()),
];
void initState() {
_navigationState = new NavigationState([
new Route(
name: '/',
builder: (navigator, route) => new HomeFragment(
builder: (navigator, route) => new FeedFragment(
navigator: navigator,
userData: _userData,
onMeasurementCreated: _handleMeasurementCreated,
onMeasurementDeleted: _handleMeasurementDeleted
onItemCreated: _handleItemCreated,
onItemDeleted: _handleItemDeleted
)
),
new Route(
name: '/meals/new',
builder: (navigator, route) => new MealFragment(
navigator: navigator,
onCreated: _handleItemCreated
)
),
new Route(
name: '/measurements/new',
builder: (navigator, route) => new MeasurementFragment(
navigator: navigator,
onCreated: _handleMeasurementCreated
onCreated: _handleItemCreated
)
),
new Route(
......@@ -54,16 +67,16 @@ class FitnessApp extends App {
}
}
void _handleMeasurementCreated(Measurement measurement) {
void _handleItemCreated(FitnessItem item) {
setState(() {
_userData.add(measurement);
_userData.add(item);
_userData.sort((a, b) => a.when.compareTo(b.when));
});
}
void _handleMeasurementDeleted(Measurement measurement) {
void _handleItemDeleted(FitnessItem item) {
setState(() {
_userData.remove(measurement);
_userData.remove(item);
});
}
......@@ -76,11 +89,6 @@ class FitnessApp extends App {
});
}
final List<Measurement> _userData = [
new Measurement(weight: 180.0, when: new DateTime.now().add(const Duration(days: -1))),
new Measurement(weight: 160.0, when: new DateTime.now()),
];
Widget build() {
return new Theme(
data: new ThemeData(
......
// Copyright 2014 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:sky/painting/text_style.dart';
import 'package:sky/editing/input.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/ink_well.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/scrollable_viewport.dart';
import 'package:sky/widgets/snack_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'fitness_item.dart';
class Meal extends FitnessItem {
Meal({ DateTime when, this.description }) : super(when: when);
final String description;
}
class MealRow extends FitnessItemRow {
MealRow({ Meal meal, FitnessItemHandler onDismissed })
: super(item: meal, onDismissed: onDismissed);
Widget buildContent() {
Meal meal = item;
List<Widget> children = [
new Flexible(
child: new Text(
meal.description,
style: const TextStyle(textAlign: TextAlign.right)
)
),
new Flexible(
child: new Text(
meal.displayDate,
style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
)
)
];
return new Flex(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(this).textBaseline
);
}
}
class MealFragment extends StatefulComponent {
MealFragment({ this.navigator, this.onCreated });
Navigator navigator;
FitnessItemHandler onCreated;
void syncFields(MealFragment source) {
navigator = source.navigator;
onCreated = source.onCreated;
}
String _description = "";
void _handleSave() {
onCreated(new Meal(when: new DateTime.now(), description: _description));
navigator.pop();
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/close",
onPressed: navigator.pop),
center: new Text('New Meal'),
right: [new InkWell(
child: new Listener(
onGestureTap: (_) => _handleSave(),
child: new Text('SAVE')
)
)]
);
}
void _handleDescriptionChanged(String description) {
setState(() {
_description = description;
});
}
Widget buildBody() {
Meal meal = new Meal(when: new DateTime.now());
return new Material(
type: MaterialType.canvas,
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.all(20.0),
child: new Block([
new Text(meal.displayDate),
new Input(
focused: false,
placeholder: 'Describe meal',
onChanged: _handleDescriptionChanged
),
])
)
)
);
}
Widget build() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildBody()
);
}
}
......@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/painting/text_style.dart';
import 'package:sky/editing/input.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/ink_well.dart';
import 'package:sky/widgets/material.dart';
......@@ -11,19 +13,46 @@ import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/scrollable_viewport.dart';
import 'package:sky/widgets/snack_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
typedef void MeasurementHandler(Measurement measurement);
import 'fitness_item.dart';
class Measurement {
Measurement({ this.when, this.weight });
class Measurement extends FitnessItem {
Measurement({ DateTime when, this.weight }) : super(when: when);
final DateTime when;
final double weight;
// TODO(jackson): Internationalize
String get displayWeight => "${weight.toStringAsFixed(2)} lbs";
String get displayDate => "${when.year.toString()}-${when.month.toString().padLeft(2,'0')}-${when.day.toString().padLeft(2,'0')}";
}
class MeasurementRow extends FitnessItemRow {
MeasurementRow({ Measurement measurement, FitnessItemHandler onDismissed })
: super(item: measurement, onDismissed: onDismissed);
Widget buildContent() {
Measurement measurement = item;
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 Flex(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(this).textBaseline
);
}
}
class MeasurementFragment extends StatefulComponent {
......@@ -31,7 +60,7 @@ class MeasurementFragment extends StatefulComponent {
MeasurementFragment({ this.navigator, this.onCreated });
Navigator navigator;
MeasurementHandler onCreated;
FitnessItemHandler onCreated;
void syncFields(MeasurementFragment source) {
navigator = source.navigator;
......@@ -76,7 +105,7 @@ class MeasurementFragment extends StatefulComponent {
});
}
Widget buildMeasurementPane() {
Widget buildBody() {
Measurement measurement = new Measurement(when: new DateTime.now());
return new Material(
type: MaterialType.canvas,
......@@ -105,7 +134,7 @@ class MeasurementFragment extends StatefulComponent {
Widget build() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildMeasurementPane(),
body: buildBody(),
snackBar: buildSnackBar()
);
}
......
......@@ -27,8 +27,6 @@ class SettingsFragment extends Component {
final BackupMode backup;
final SettingsUpdater updater;
bool showModeDialog = false;
void _handleBackupChanged(bool value) {
if (updater != null)
updater(backup: value ? BackupMode.enabled : BackupMode.disabled);
......
// 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.
......@@ -57,6 +56,20 @@ class MineDiggerApp extends App {
// |uiState| keeps track of the visible player progess.
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));
initialize();
}
void resetGame() {
alive = true;
hasWon = false;
......@@ -148,13 +161,14 @@ class MineDiggerApp extends App {
} else if (state == CellState.flagged) {
row.add(new CoveredMineNode(
flagged: true,
posX: ix, posY: iy)
);
posX: ix,
posY: iy
));
} else {
row.add(new ExposedMineNode(
state: state,
count: count)
);
count: count
));
}
}
flexRows.add(
......@@ -162,8 +176,9 @@ class MineDiggerApp extends App {
row,
direction: FlexDirection.horizontal,
justifyContent: FlexJustifyContent.center,
key: 'flex_row($iy)'
));
key: new Key.stringify(iy)
)
);
}
if (!hasCoveredCell) {
......
......@@ -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, (_) {
......@@ -140,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,
......@@ -264,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;
......
......@@ -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,13 +27,13 @@ class CardModel {
Color color;
AnimationPerformance performance;
String get label => "Item $value";
String get key => value.toString();
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]
);
}
......
......@@ -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
);
......
......@@ -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;
}
This diff is collapsed.
......@@ -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,
......
......@@ -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;
......
......@@ -46,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,
......@@ -190,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;
......@@ -242,7 +242,7 @@ class Navigator extends StatefulComponent {
if (content == null)
continue;
Transition transition = new Transition(
key: historyEntry.hashCode.toString(), // TODO(ianh): make it not collide
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,
......
......@@ -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,
......
......@@ -12,7 +12,7 @@ export 'package:sky/widgets/block_viewport.dart' show BlockViewportLayoutState;
class VariableHeightScrollable extends Scrollable {
VariableHeightScrollable({
String key,
Key key,
this.builder,
this.token,
this.layoutState
......
......@@ -21,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
///
......@@ -46,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;
......@@ -243,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;
......@@ -284,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)) {
......@@ -320,7 +352,7 @@ typedef void EventListener(sky.Event e);
class Listener extends TagNode {
Listener({
String key,
Key key,
Widget child,
EventListener onWheel,
GestureEventListener onGestureFlingCancel,
......@@ -407,7 +439,7 @@ class Listener extends TagNode {
abstract class Component extends Widget {
Component({ String key })
Component({ Key key })
: _order = _currentOrder + 1,
super._withKey(key);
......@@ -524,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;
......@@ -599,11 +631,13 @@ int _inLayoutCallbackBuilder = 0;
class LayoutCallbackBuilderHandle { bool _active = true; }
LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() {
LayoutCallbackBuilderHandle result;
assert(() {
_inLayoutCallbackBuilder += 1;
result = new LayoutCallbackBuilderHandle();
return true;
});
return new LayoutCallbackBuilderHandle();
return result;
}
void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) {
assert(() {
......@@ -682,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();
......@@ -766,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);
......@@ -780,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;
......@@ -828,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());
......@@ -867,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)
......@@ -922,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;
......@@ -942,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)
......@@ -1047,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')
......@@ -1095,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;
}
......
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