Commit 79c88b4d authored by Kris Giesing's avatar Kris Giesing

Merge remote-tracking branch 'upstream/master'

parents 43a5dff8 cf17dd96
...@@ -53,14 +53,12 @@ class AddressBookHome extends StatelessComponent { ...@@ -53,14 +53,12 @@ class AddressBookHome extends StatelessComponent {
); );
} }
static final GlobalKey nameKey = new GlobalKey(); static final GlobalKey nameKey = new GlobalKey(label: 'name field');
static final GlobalKey phoneKey = new GlobalKey(); static final GlobalKey phoneKey = new GlobalKey(label: 'phone field');
static final GlobalKey emailKey = new GlobalKey(); static final GlobalKey emailKey = new GlobalKey(label: 'email field');
static final GlobalKey addressKey = new GlobalKey(); static final GlobalKey addressKey = new GlobalKey(label: 'address field');
static final GlobalKey ringtoneKey = new GlobalKey(); static final GlobalKey ringtoneKey = new GlobalKey(label: 'ringtone field');
static final GlobalKey noteKey = new GlobalKey(); static final GlobalKey noteKey = new GlobalKey(label: 'note field');
static final GlobalKey fillKey = new GlobalKey();
static final GlobalKey emoticonKey = new GlobalKey();
Widget buildBody(BuildContext context) { Widget buildBody(BuildContext context) {
return new Material( return new Material(
...@@ -83,7 +81,7 @@ class AddressBookHome extends StatelessComponent { ...@@ -83,7 +81,7 @@ class AddressBookHome extends StatelessComponent {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(context), toolBar: buildToolBar(context),
body: buildBody(context), body: buildBody(context),
floatingActionButton: buildFloatingActionButton(context) floatingActionButton: buildFloatingActionButton(context)
); );
......
...@@ -192,7 +192,7 @@ final ThemeData _theme = new ThemeData( ...@@ -192,7 +192,7 @@ final ThemeData _theme = new ThemeData(
class DemoHome extends StatelessComponent { class DemoHome extends StatelessComponent {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: new ToolBar(center: new Text('Sky Demos')), toolBar: new ToolBar(center: new Text('Sky Demos')),
body: new Material( body: new Material(
type: MaterialType.canvas, type: MaterialType.canvas,
child: new DemoList() child: new DemoList()
......
...@@ -58,11 +58,9 @@ class FeedFragment extends StatefulComponent { ...@@ -58,11 +58,9 @@ class FeedFragment extends StatefulComponent {
} }
class FeedFragmentState extends State<FeedFragment> { class FeedFragmentState extends State<FeedFragment> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
FitnessMode _fitnessMode = FitnessMode.feed; FitnessMode _fitnessMode = FitnessMode.feed;
PerformanceStatus _snackBarStatus = PerformanceStatus.dismissed;
bool _isShowingSnackBar = false;
void _handleFitnessModeChange(FitnessMode value) { void _handleFitnessModeChange(FitnessMode value) {
setState(() { setState(() {
_fitnessMode = value; _fitnessMode = value;
...@@ -119,15 +117,17 @@ class FeedFragmentState extends State<FeedFragment> { ...@@ -119,15 +117,17 @@ class FeedFragmentState extends State<FeedFragment> {
); );
} }
FitnessItem _undoItem;
void _handleItemDismissed(FitnessItem item) { void _handleItemDismissed(FitnessItem item) {
config.onItemDeleted(item); config.onItemDeleted(item);
setState(() { showSnackBar(
_undoItem = item; navigator: config.navigator,
_isShowingSnackBar = true; placeholderKey: _snackBarPlaceholderKey,
_snackBarStatus = PerformanceStatus.forward; content: new Text("Item deleted."),
}); actions: [new SnackBarAction(label: "UNDO", onPressed: () {
config.onItemCreated(item);
config.navigator.pop();
})]
);
} }
Widget buildChart() { Widget buildChart() {
...@@ -198,25 +198,6 @@ class FeedFragmentState extends State<FeedFragment> { ...@@ -198,25 +198,6 @@ class FeedFragmentState extends State<FeedFragment> {
} }
} }
void _handleUndo() {
config.onItemCreated(_undoItem);
setState(() {
_undoItem = null;
_isShowingSnackBar = false;
});
}
Widget buildSnackBar() {
if (_snackBarStatus == PerformanceStatus.dismissed)
return null;
return new SnackBar(
showing: _isShowingSnackBar,
content: new Text("Item deleted."),
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
onDismissed: () { setState(() { _snackBarStatus = PerformanceStatus.dismissed; }); }
);
}
void _handleActionButtonPressed() { void _handleActionButtonPressed() {
showDialog(config.navigator, (NavigatorState navigator) => new AddItemDialog(navigator)).then((routeName) { showDialog(config.navigator, (NavigatorState navigator) => new AddItemDialog(navigator)).then((routeName) {
if (routeName != null) if (routeName != null)
...@@ -238,9 +219,9 @@ class FeedFragmentState extends State<FeedFragment> { ...@@ -238,9 +219,9 @@ class FeedFragmentState extends State<FeedFragment> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: buildBody(), body: buildBody(),
snackBar: buildSnackBar(), snackBar: new Placeholder(key: _snackBarPlaceholderKey),
floatingActionButton: buildFloatingActionButton() floatingActionButton: buildFloatingActionButton()
); );
} }
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
library fitness; library fitness;
import 'package:playfair/playfair.dart' as playfair; import 'package:playfair/playfair.dart' as playfair;
import 'package:sky/animation.dart';
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/painting.dart'; import 'package:sky/painting.dart';
import 'package:sky/widgets.dart'; import 'package:sky/widgets.dart';
......
...@@ -105,7 +105,7 @@ class MealFragmentState extends State<MealFragment> { ...@@ -105,7 +105,7 @@ class MealFragmentState extends State<MealFragment> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: buildBody() body: buildBody()
); );
} }
......
...@@ -112,9 +112,10 @@ class MeasurementFragment extends StatefulComponent { ...@@ -112,9 +112,10 @@ class MeasurementFragment extends StatefulComponent {
} }
class MeasurementFragmentState extends State<MeasurementFragment> { class MeasurementFragmentState extends State<MeasurementFragment> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
String _weight = ""; String _weight = "";
DateTime _when = new DateTime.now(); DateTime _when = new DateTime.now();
String _errorMessage = null;
void _handleSave() { void _handleSave() {
double parsedWeight; double parsedWeight;
...@@ -122,9 +123,11 @@ class MeasurementFragmentState extends State<MeasurementFragment> { ...@@ -122,9 +123,11 @@ class MeasurementFragmentState extends State<MeasurementFragment> {
parsedWeight = double.parse(_weight); parsedWeight = double.parse(_weight);
} on FormatException catch(e) { } on FormatException catch(e) {
print("Exception $e"); print("Exception $e");
setState(() { showSnackBar(
_errorMessage = "Save failed"; navigator: config.navigator,
}); placeholderKey: _snackBarPlaceholderKey,
content: new Text('Save failed')
);
} }
config.onCreated(new Measurement(when: _when, weight: parsedWeight)); config.onCreated(new Measurement(when: _when, weight: parsedWeight));
config.navigator.pop(); config.navigator.pop();
...@@ -195,18 +198,11 @@ class MeasurementFragmentState extends State<MeasurementFragment> { ...@@ -195,18 +198,11 @@ class MeasurementFragmentState extends State<MeasurementFragment> {
); );
} }
Widget buildSnackBar() {
if (_errorMessage == null)
return null;
// TODO(jackson): This doesn't show up, unclear why.
return new SnackBar(content: new Text(_errorMessage), showing: true);
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: buildBody(context), body: buildBody(context),
snackBar: buildSnackBar() snackBar: new Placeholder(key: _snackBarPlaceholderKey)
); );
} }
} }
...@@ -122,7 +122,7 @@ class SettingsFragmentState extends State<SettingsFragment> { ...@@ -122,7 +122,7 @@ class SettingsFragmentState extends State<SettingsFragment> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: buildSettingsPane(context) body: buildSettingsPane(context)
); );
} }
......
...@@ -119,8 +119,10 @@ class GameDemoState extends State<GameDemo> { ...@@ -119,8 +119,10 @@ class GameDemoState extends State<GameDemo> {
width: 128.0, width: 128.0,
height: 128.0 height: 128.0
), ),
new Text( new DefaultTextStyle(
"Last Score: $_lastScore", child: new Text(
"Last Score: $_lastScore"
),
style: new TextStyle(fontSize:20.0) style: new TextStyle(fontSize:20.0)
) )
], ],
......
...@@ -182,7 +182,7 @@ class MineDiggerState extends State<MineDigger> { ...@@ -182,7 +182,7 @@ class MineDiggerState extends State<MineDigger> {
return new Title( return new Title(
title: 'Mine Digger', title: 'Mine Digger',
child: new Scaffold( child: new Scaffold(
toolbar: buildToolBar(context), toolBar: buildToolBar(context),
body: new Container( body: new Container(
child: new Center(child: board), child: new Center(child: board),
decoration: new BoxDecoration(backgroundColor: Colors.grey[50]) decoration: new BoxDecoration(backgroundColor: Colors.grey[50])
......
...@@ -8,7 +8,6 @@ import 'dart:async'; ...@@ -8,7 +8,6 @@ import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:sky' as sky; import 'dart:sky' as sky;
import 'package:sky/animation.dart';
import 'package:sky/gestures.dart'; import 'package:sky/gestures.dart';
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/painting.dart'; import 'package:sky/painting.dart';
......
...@@ -6,8 +6,6 @@ part of stocks; ...@@ -6,8 +6,6 @@ part of stocks;
typedef void ModeUpdater(StockMode mode); typedef void ModeUpdater(StockMode mode);
const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200);
class StockHome extends StatefulComponent { class StockHome extends StatefulComponent {
StockHome(this.navigator, this.stocks, this.symbols, this.stockMode, this.modeUpdater); StockHome(this.navigator, this.stocks, this.symbols, this.stockMode, this.modeUpdater);
...@@ -22,12 +20,10 @@ class StockHome extends StatefulComponent { ...@@ -22,12 +20,10 @@ class StockHome extends StatefulComponent {
class StockHomeState extends State<StockHome> { class StockHomeState extends State<StockHome> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
bool _isSearching = false; bool _isSearching = false;
String _searchQuery; String _searchQuery;
PerformanceStatus _snackBarStatus = PerformanceStatus.dismissed;
bool _isSnackBarShowing = false;
void _handleSearchBegin() { void _handleSearchBegin() {
config.navigator.pushState(this, (_) { config.navigator.pushState(this, (_) {
setState(() { setState(() {
...@@ -130,22 +126,23 @@ class StockHomeState extends State<StockHome> { ...@@ -130,22 +126,23 @@ class StockHomeState extends State<StockHome> {
Widget buildToolBar() { Widget buildToolBar() {
return new ToolBar( return new ToolBar(
left: new IconButton( level: 0,
icon: "navigation/menu", left: new IconButton(
onPressed: _showDrawer icon: "navigation/menu",
onPressed: _showDrawer
),
center: new Text('Stocks'),
right: [
new IconButton(
icon: "action/search",
onPressed: _handleSearchBegin
), ),
center: new Text('Stocks'), new IconButton(
right: [ icon: "navigation/more_vert",
new IconButton( onPressed: _handleMenuShow
icon: "action/search", )
onPressed: _handleSearchBegin ]
), );
new IconButton(
icon: "navigation/more_vert",
onPressed: _handleMenuShow
)
]
);
} }
int selectedTabIndex = 0; int selectedTabIndex = 0;
...@@ -217,30 +214,20 @@ class StockHomeState extends State<StockHome> { ...@@ -217,30 +214,20 @@ class StockHomeState extends State<StockHome> {
} }
void _handleUndo() { void _handleUndo() {
setState(() { config.navigator.pop();
_isSnackBarShowing = false;
});
} }
GlobalKey snackBarKey = new GlobalKey(label: 'snackbar'); void _handleStockPurchased() {
Widget buildSnackBar() { showSnackBar(
if (_snackBarStatus == PerformanceStatus.dismissed) navigator: config.navigator,
return null; placeholderKey: _snackBarPlaceholderKey,
return new SnackBar(
showing: _isSnackBarShowing,
content: new Text("Stock purchased!"), content: new Text("Stock purchased!"),
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)], actions: [
onDismissed: () { setState(() { _snackBarStatus = PerformanceStatus.dismissed; }); } new SnackBarAction(label: "UNDO", onPressed: _handleUndo)
]
); );
} }
void _handleStockPurchased() {
setState(() {
_isSnackBarShowing = true;
_snackBarStatus = PerformanceStatus.forward;
});
}
Widget buildFloatingActionButton() { Widget buildFloatingActionButton() {
return new FloatingActionButton( return new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24), child: new Icon(type: 'content/add', size: 24),
...@@ -251,9 +238,9 @@ class StockHomeState extends State<StockHome> { ...@@ -251,9 +238,9 @@ class StockHomeState extends State<StockHome> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: _isSearching ? buildSearchBar() : buildToolBar(), toolBar: _isSearching ? buildSearchBar() : buildToolBar(),
body: buildTabNavigator(), body: buildTabNavigator(),
snackBar: buildSnackBar(), snackBar: new Placeholder(key: _snackBarPlaceholderKey),
floatingActionButton: buildFloatingActionButton() floatingActionButton: buildFloatingActionButton()
); );
} }
......
...@@ -6,12 +6,14 @@ part of stocks; ...@@ -6,12 +6,14 @@ part of stocks;
enum _MenuItems { autorefresh, autorefreshCheckbox, add, remove } enum _MenuItems { autorefresh, autorefreshCheckbox, add, remove }
const double _kMenuMargin = 16.0; // 24.0 on tablet
Future showStockMenu(NavigatorState navigator, { bool autorefresh, ValueChanged onAutorefreshChanged }) async { Future showStockMenu(NavigatorState navigator, { bool autorefresh, ValueChanged onAutorefreshChanged }) async {
switch (await showMenu( switch (await showMenu(
navigator: navigator, navigator: navigator,
position: new MenuPosition( position: new MenuPosition(
right: sky.view.paddingRight, right: sky.view.paddingRight + _kMenuMargin,
top: sky.view.paddingTop top: sky.view.paddingTop + _kMenuMargin
), ),
builder: (NavigatorState navigator) { builder: (NavigatorState navigator) {
return <PopupMenuItem>[ return <PopupMenuItem>[
......
...@@ -119,7 +119,7 @@ class StockSettingsState extends State<StockSettings> { ...@@ -119,7 +119,7 @@ class StockSettingsState extends State<StockSettings> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(context), toolBar: buildToolBar(context),
body: buildSettingsPane(context) body: buildSettingsPane(context)
); );
} }
......
...@@ -25,7 +25,7 @@ class StockSymbolViewerState extends State<StockSymbolViewer> { ...@@ -25,7 +25,7 @@ class StockSymbolViewerState extends State<StockSymbolViewer> {
TextStyle headings = Theme.of(context).text.body2; TextStyle headings = Theme.of(context).text.body2;
return new Scaffold( return new Scaffold(
toolbar: new ToolBar( toolBar: new ToolBar(
left: new IconButton( left: new IconButton(
icon: 'navigation/arrow_back', icon: 'navigation/arrow_back',
onPressed: config.navigator.pop onPressed: config.navigator.pop
......
...@@ -342,7 +342,7 @@ class CardCollectionState extends State<CardCollection> { ...@@ -342,7 +342,7 @@ class CardCollectionState extends State<CardCollection> {
} }
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: body body: body
); );
} }
......
...@@ -34,7 +34,7 @@ class DatePickerDemoState extends State<DatePickerDemo> { ...@@ -34,7 +34,7 @@ class DatePickerDemoState extends State<DatePickerDemo> {
), ),
child: new Stack([ child: new Stack([
new Scaffold( new Scaffold(
toolbar: new ToolBar(center: new Text("Date Picker")), toolBar: new ToolBar(center: new Text("Date Picker")),
body: new Material( body: new Material(
child: new Row( child: new Row(
[new Text(_dateTime.toString())], [new Text(_dateTime.toString())],
......
...@@ -101,7 +101,7 @@ class DragAndDropApp extends StatefulComponent { ...@@ -101,7 +101,7 @@ class DragAndDropApp extends StatefulComponent {
class DragAndDropAppState extends State<DragAndDropApp> { class DragAndDropAppState extends State<DragAndDropApp> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolbar: new ToolBar( toolBar: new ToolBar(
center: new Text('Drag and Drop Flutter Demo') center: new Text('Drag and Drop Flutter Demo')
), ),
body: new Material( body: new Material(
......
...@@ -89,7 +89,7 @@ class EnsureVisibleApp extends App { ...@@ -89,7 +89,7 @@ class EnsureVisibleApp extends App {
child: new Title( child: new Title(
title: 'Cards', title: 'Cards',
child: new Scaffold( child: new Scaffold(
toolbar: new ToolBar(center: new Text('Tap a Card')), toolBar: new ToolBar(center: new Text('Tap a Card')),
body: cardCollection body: cardCollection
) )
) )
......
...@@ -138,7 +138,7 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> { ...@@ -138,7 +138,7 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> layers = <Widget>[ List<Widget> layers = <Widget>[
new Scaffold( new Scaffold(
toolbar: new ToolBar(center: new Text('Tap a Card')), toolBar: new ToolBar(center: new Text('Tap a Card')),
body: new Container( body: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0), padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]), decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
......
...@@ -149,7 +149,7 @@ class PageableListAppState extends State<PageableListApp> { ...@@ -149,7 +149,7 @@ class PageableListAppState extends State<PageableListApp> {
return new IconTheme( return new IconTheme(
data: const IconThemeData(color: IconThemeColor.white), data: const IconThemeData(color: IconThemeColor.white),
child: new Scaffold( child: new Scaffold(
toolbar: buildToolBar(), toolBar: buildToolBar(),
body: buildBody(context) body: buildBody(context)
) )
); );
......
...@@ -103,7 +103,7 @@ class ProgressIndicatorAppState extends State<ProgressIndicatorApp> { ...@@ -103,7 +103,7 @@ class ProgressIndicatorAppState extends State<ProgressIndicatorApp> {
child: new Title( child: new Title(
title: 'Progress Indicators', title: 'Progress Indicators',
child: new Scaffold( child: new Scaffold(
toolbar: new ToolBar(center: new Text('Progress Indicators')), toolBar: new ToolBar(center: new Text('Progress Indicators')),
body: new DefaultTextStyle( body: new DefaultTextStyle(
style: Theme.of(context).text.title, style: Theme.of(context).text.title,
child: body child: body
......
...@@ -59,7 +59,7 @@ class ScaleAppState extends State<ScaleApp> { ...@@ -59,7 +59,7 @@ class ScaleAppState extends State<ScaleApp> {
return new Theme( return new Theme(
data: new ThemeData.dark(), data: new ThemeData.dark(),
child: new Scaffold( child: new Scaffold(
toolbar: new ToolBar( toolBar: new ToolBar(
center: new Text('Scale Demo')), center: new Text('Scale Demo')),
body: new Material( body: new Material(
type: MaterialType.canvas, type: MaterialType.canvas,
......
...@@ -124,7 +124,7 @@ class SectorApp extends App { ...@@ -124,7 +124,7 @@ class SectorApp extends App {
child: new Title( child: new Title(
title: 'Sector Layout', title: 'Sector Layout',
child: new Scaffold( child: new Scaffold(
toolbar: new ToolBar( toolBar: new ToolBar(
center: new Text('Sector Layout in a Widget Tree') center: new Text('Sector Layout in a Widget Tree')
), ),
body: buildBody() body: buildBody()
......
...@@ -106,7 +106,7 @@ HAL: This mission is too important for me to allow you to jeopardize it.'''; ...@@ -106,7 +106,7 @@ HAL: This mission is too important for me to allow you to jeopardize it.''';
color: Colors.grey[50], color: Colors.grey[50],
child: interactiveBody child: interactiveBody
), ),
toolbar: new ToolBar( toolBar: new ToolBar(
center: new Text('Hal and Dave') center: new Text('Hal and Dave')
) )
) )
......
...@@ -131,7 +131,7 @@ class TabbedNavigatorAppState extends State<TabbedNavigatorApp> { ...@@ -131,7 +131,7 @@ class TabbedNavigatorAppState extends State<TabbedNavigatorApp> {
); );
return new Scaffold( return new Scaffold(
toolbar: toolbar, toolBar: toolbar,
body: tabNavigator body: tabNavigator
); );
} }
......
...@@ -16,6 +16,7 @@ export 'src/services/asset_bundle.dart'; ...@@ -16,6 +16,7 @@ export 'src/services/asset_bundle.dart';
export 'src/services/embedder.dart'; export 'src/services/embedder.dart';
export 'src/services/fetch.dart'; export 'src/services/fetch.dart';
export 'src/services/image_cache.dart'; export 'src/services/image_cache.dart';
export 'src/services/image_decoder.dart';
export 'src/services/image_resource.dart'; export 'src/services/image_resource.dart';
export 'src/services/keyboard.dart'; export 'src/services/keyboard.dart';
export 'src/services/shell.dart'; export 'src/services/shell.dart';
...@@ -14,10 +14,12 @@ const double kStatusBarHeight = 50.0; ...@@ -14,10 +14,12 @@ const double kStatusBarHeight = 50.0;
// Mobile Portrait: 56dp // Mobile Portrait: 56dp
// Tablet/Desktop: 64dp // Tablet/Desktop: 64dp
const double kToolBarHeight = 56.0; const double kToolBarHeight = 56.0;
const double kSnackBarHeight = 52.0;
const double kMaterialDrawerHeight = 140.0; const double kMaterialDrawerHeight = 140.0;
const double kScrollbarSize = 10.0; const double kScrollbarSize = 10.0;
const double kScrollbarFadeDuration = 250.0; const Duration kScrollbarFadeDuration = const Duration(milliseconds: 250);
const double kScrollbarFadeDelay = 300.0; const Duration kScrollbarFadeDelay = const Duration(milliseconds: 300);
const double kFadingEdgeLength = 12.0; const double kFadingEdgeLength = 12.0;
const double kPressedStateDuration = 64.0; const double kPressedStateDuration = 64.0; // units?
const Duration kThemeChangeDuration = const Duration(milliseconds: 200);
...@@ -11,6 +11,7 @@ import 'package:mojo/core.dart' as core; ...@@ -11,6 +11,7 @@ import 'package:mojo/core.dart' as core;
import 'package:mojo_services/mojo/asset_bundle/asset_bundle.mojom.dart'; import 'package:mojo_services/mojo/asset_bundle/asset_bundle.mojom.dart';
import 'package:sky/src/services/fetch.dart'; import 'package:sky/src/services/fetch.dart';
import 'package:sky/src/services/image_cache.dart'; import 'package:sky/src/services/image_cache.dart';
import 'package:sky/src/services/image_decoder.dart';
import 'package:sky/src/services/image_resource.dart'; import 'package:sky/src/services/image_resource.dart';
import 'package:sky/src/services/shell.dart'; import 'package:sky/src/services/shell.dart';
...@@ -66,13 +67,13 @@ class MojoAssetBundle extends AssetBundle { ...@@ -66,13 +67,13 @@ class MojoAssetBundle extends AssetBundle {
_imageCache = null; _imageCache = null;
} }
Future<sky.Image> _fetchImage(String key) async {
return await decodeImageFromDataPipe(await load(key));
}
ImageResource loadImage(String key) { ImageResource loadImage(String key) {
return _imageCache.putIfAbsent(key, () { return _imageCache.putIfAbsent(key, () {
Completer<sky.Image> completer = new Completer<sky.Image>(); return new ImageResource(_fetchImage(key));
load(key).then((assetData) {
new sky.ImageDecoder.consume(assetData.handle.h, completer.complete);
});
return new ImageResource(completer.future);
}); });
} }
......
...@@ -7,8 +7,18 @@ import 'dart:collection'; ...@@ -7,8 +7,18 @@ import 'dart:collection';
import 'dart:sky' as sky; import 'dart:sky' as sky;
import 'package:mojo/mojo/url_response.mojom.dart'; import 'package:mojo/mojo/url_response.mojom.dart';
import 'package:sky/src/services/image_resource.dart';
import 'package:sky/src/services/fetch.dart'; import 'package:sky/src/services/fetch.dart';
import 'package:sky/src/services/image_decoder.dart';
import 'package:sky/src/services/image_resource.dart';
Future<sky.Image> _fetchImage(String url) async {
UrlResponse response = await fetchUrl(url);
if (response.statusCode >= 400) {
print("Failed (${response.statusCode}) to load image ${url}");
return null;
}
return await decodeImageFromDataPipe(response.body);
}
class _ImageCache { class _ImageCache {
_ImageCache._(); _ImageCache._();
...@@ -17,16 +27,7 @@ class _ImageCache { ...@@ -17,16 +27,7 @@ class _ImageCache {
ImageResource load(String url) { ImageResource load(String url) {
return _cache.putIfAbsent(url, () { return _cache.putIfAbsent(url, () {
Completer<sky.Image> completer = new Completer<sky.Image>(); return new ImageResource(_fetchImage(url));
fetchUrl(url).then((UrlResponse response) {
if (response.statusCode >= 400) {
print("Failed (${response.statusCode}) to load image ${url}");
completer.complete(null);
} else {
new sky.ImageDecoder.consume(response.body.handle.h, completer.complete);
}
});
return new ImageResource(completer.future);
}); });
} }
} }
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:sky' show Image, ImageDecoder, ImageDecoderCallback;
import 'dart:typed_data';
import 'package:mojo/core.dart' show MojoDataPipeConsumer;
final Set<ImageDecoder> _activeDecoders = new Set<ImageDecoder>();
typedef ImageDecoder _DecoderFactory(ImageDecoderCallback callback);
Future<Image> _decode(_DecoderFactory createDecoder) {
Completer<Image> completer = new Completer<Image>();
ImageDecoder decoder;
decoder = createDecoder((Image image) {
_activeDecoders.remove(decoder);
completer.complete(image);
});
_activeDecoders.add(decoder);
return completer.future;
}
Future<Image> decodeImageFromDataPipe(MojoDataPipeConsumer consumerHandle) {
return _decode((ImageDecoderCallback callback) => new ImageDecoder.consume(consumerHandle.handle.h, callback));
}
Future<Image> decodeImageFromList(Uint8List list) {
return _decode((ImageDecoderCallback callback) => new ImageDecoder.fromList(list, callback));
}
// 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/animation.dart';
import 'package:sky/src/widgets/framework.dart';
abstract class AnimatedComponent extends StatefulComponent {
const AnimatedComponent({ Key key, this.direction, this.duration }) : super(key: key);
final Duration duration;
final AnimationDirection direction;
}
abstract class AnimatedState<T extends AnimatedComponent> extends State<T> {
void initState() {
super.initState();
_performance = new Performance(duration: config.duration);
performance.addStatusListener(_handleAnimationStatusChanged);
if (buildDependsOnPerformance) {
performance.addListener(() {
setState(() {
// We don't actually have any state to change, per se,
// we just know that we have in fact changed state.
});
});
}
performance.play(config.direction);
}
void didUpdateConfig(T oldConfig) {
performance.duration = config.duration;
if (config.duration != oldConfig.duration || config.direction != oldConfig.direction)
performance.play(config.direction);
}
Performance get performance => _performance;
Performance _performance;
void _handleAnimationStatusChanged(PerformanceStatus status) {
if (status == PerformanceStatus.completed)
handleCompleted();
else if (status == PerformanceStatus.dismissed)
handleDismissed();
}
bool get buildDependsOnPerformance => false;
void handleCompleted() { }
void handleDismissed() { }
}
...@@ -77,10 +77,10 @@ class AnimatedContainer extends StatefulComponent { ...@@ -77,10 +77,10 @@ class AnimatedContainer extends StatefulComponent {
final Curve curve; final Curve curve;
final Duration duration; final Duration duration;
AnimatedContainerState createState() => new AnimatedContainerState(); _AnimatedContainerState createState() => new _AnimatedContainerState();
} }
class AnimatedContainerState extends State<AnimatedContainer> { class _AnimatedContainerState extends State<AnimatedContainer> {
AnimatedBoxConstraintsValue _constraints; AnimatedBoxConstraintsValue _constraints;
AnimatedBoxDecorationValue _decoration; AnimatedBoxDecorationValue _decoration;
AnimatedBoxDecorationValue _foregroundDecoration; AnimatedBoxDecorationValue _foregroundDecoration;
......
...@@ -38,7 +38,7 @@ class App extends StatefulComponent { ...@@ -38,7 +38,7 @@ class App extends StatefulComponent {
'This might be a sign that you have not upgraded to our new Widgets framework.'; 'This might be a sign that you have not upgraded to our new Widgets framework.';
'For more details see: https://groups.google.com/forum/#!topic/flutter-dev/hcX3OvLws9c'; 'For more details see: https://groups.google.com/forum/#!topic/flutter-dev/hcX3OvLws9c';
'...or look at our examples: https://github.com/flutter/engine/tree/master/examples'; '...or look at our examples: https://github.com/flutter/engine/tree/master/examples';
return routes != null; return routes != null;
}); });
} }
...@@ -47,10 +47,10 @@ class App extends StatefulComponent { ...@@ -47,10 +47,10 @@ class App extends StatefulComponent {
final Map<String, RouteBuilder> routes; final Map<String, RouteBuilder> routes;
final RouteGenerator onGenerateRoute; final RouteGenerator onGenerateRoute;
AppState createState() => new AppState(); _AppState createState() => new _AppState();
} }
class AppState extends State<App> { class _AppState extends State<App> {
GlobalObjectKey _navigator; GlobalObjectKey _navigator;
......
...@@ -808,10 +808,10 @@ class ImageListener extends StatefulComponent { ...@@ -808,10 +808,10 @@ class ImageListener extends StatefulComponent {
final ImageFit fit; final ImageFit fit;
final ImageRepeat repeat; final ImageRepeat repeat;
ImageListenerState createState() => new ImageListenerState(); _ImageListenerState createState() => new _ImageListenerState();
} }
class ImageListenerState extends State<ImageListener> { class _ImageListenerState extends State<ImageListener> {
void initState() { void initState() {
super.initState(); super.initState();
config.image.addListener(_handleImageChanged); config.image.addListener(_handleImageChanged);
......
...@@ -41,7 +41,7 @@ class WidgetFlutterBinding extends FlutterBinding { ...@@ -41,7 +41,7 @@ class WidgetFlutterBinding extends FlutterBinding {
Element.finalizeTree(); Element.finalizeTree();
} }
List<BuildableElement> _dirtyElements = new List<BuildableElement>(); List<BuildableElement> _dirtyElements = <BuildableElement>[];
/// Adds an element to the dirty elements list so that it will be rebuilt /// Adds an element to the dirty elements list so that it will be rebuilt
/// when buildDirtyElements is called. /// when buildDirtyElements is called.
...@@ -62,10 +62,19 @@ class WidgetFlutterBinding extends FlutterBinding { ...@@ -62,10 +62,19 @@ class WidgetFlutterBinding extends FlutterBinding {
return; return;
BuildableElement.lockState(() { BuildableElement.lockState(() {
_dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth); _dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth);
for (BuildableElement element in _dirtyElements) int dirtyCount = _dirtyElements.length;
element.rebuild(); int index = 0;
while (index < dirtyCount) {
_dirtyElements[index].rebuild();
index += 1;
if (dirtyCount < _dirtyElements.length) {
_dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth);
dirtyCount = _dirtyElements.length;
}
}
assert(!_dirtyElements.any((BuildableElement element) => element.dirty));
_dirtyElements.clear(); _dirtyElements.clear();
}); }, building: true);
assert(_dirtyElements.isEmpty); assert(_dirtyElements.isEmpty);
} }
} }
...@@ -76,7 +85,7 @@ void runApp(Widget app) { ...@@ -76,7 +85,7 @@ void runApp(Widget app) {
WidgetFlutterBinding.instance.renderViewElement.update( WidgetFlutterBinding.instance.renderViewElement.update(
WidgetFlutterBinding.instance.describeApp(app) WidgetFlutterBinding.instance.describeApp(app)
); );
}); }, building: true);
} }
void debugDumpApp() { void debugDumpApp() {
......
...@@ -39,10 +39,10 @@ class DatePicker extends StatefulComponent { ...@@ -39,10 +39,10 @@ class DatePicker extends StatefulComponent {
final DateTime firstDate; final DateTime firstDate;
final DateTime lastDate; final DateTime lastDate;
DatePickerState createState() => new DatePickerState(); _DatePickerState createState() => new _DatePickerState();
} }
class DatePickerState extends State<DatePicker> { class _DatePickerState extends State<DatePicker> {
DatePickerMode _mode = DatePickerMode.day; DatePickerMode _mode = DatePickerMode.day;
void _handleModeChanged(DatePickerMode mode) { void _handleModeChanged(DatePickerMode mode) {
...@@ -70,7 +70,7 @@ class DatePickerState extends State<DatePicker> { ...@@ -70,7 +70,7 @@ class DatePickerState extends State<DatePicker> {
static const double _calendarHeight = 210.0; static const double _calendarHeight = 210.0;
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget header = new DatePickerHeader( Widget header = new _DatePickerHeader(
selectedDate: config.selectedDate, selectedDate: config.selectedDate,
mode: _mode, mode: _mode,
onModeChanged: _handleModeChanged onModeChanged: _handleModeChanged
...@@ -107,8 +107,8 @@ class DatePickerState extends State<DatePicker> { ...@@ -107,8 +107,8 @@ class DatePickerState extends State<DatePicker> {
} }
// Shows the selected date in large font and toggles between year and day mode // Shows the selected date in large font and toggles between year and day mode
class DatePickerHeader extends StatelessComponent { class _DatePickerHeader extends StatelessComponent {
DatePickerHeader({ this.selectedDate, this.mode, this.onModeChanged }) { _DatePickerHeader({ this.selectedDate, this.mode, this.onModeChanged }) {
assert(selectedDate != null); assert(selectedDate != null);
assert(mode != null); assert(mode != null);
} }
...@@ -290,10 +290,10 @@ class MonthPicker extends ScrollableWidgetList { ...@@ -290,10 +290,10 @@ class MonthPicker extends ScrollableWidgetList {
final DateTime firstDate; final DateTime firstDate;
final DateTime lastDate; final DateTime lastDate;
MonthPickerState createState() => new MonthPickerState(); _MonthPickerState createState() => new _MonthPickerState();
} }
class MonthPickerState extends ScrollableWidgetListState<MonthPicker> { class _MonthPickerState extends ScrollableWidgetListState<MonthPicker> {
void initState() { void initState() {
super.initState(); super.initState();
_updateCurrentDate(); _updateCurrentDate();
...@@ -363,10 +363,10 @@ class YearPicker extends ScrollableWidgetList { ...@@ -363,10 +363,10 @@ class YearPicker extends ScrollableWidgetList {
final DateTime firstDate; final DateTime firstDate;
final DateTime lastDate; final DateTime lastDate;
YearPickerState createState() => new YearPickerState(); _YearPickerState createState() => new _YearPickerState();
} }
class YearPickerState extends ScrollableWidgetListState<YearPicker> { class _YearPickerState extends ScrollableWidgetListState<YearPicker> {
int get itemCount => config.lastDate.year - config.firstDate.year + 1; int get itemCount => config.lastDate.year - config.firstDate.year + 1;
List<Widget> buildItems(BuildContext context, int start, int count) { List<Widget> buildItems(BuildContext context, int start, int count) {
......
...@@ -131,16 +131,15 @@ class Dialog extends StatelessComponent { ...@@ -131,16 +131,15 @@ class Dialog extends StatelessComponent {
} }
} }
const Duration _kTransitionDuration = const Duration(milliseconds: 150); class _DialogRoute extends Route {
_DialogRoute({ this.completer, this.builder });
class DialogRoute extends Route {
DialogRoute({ this.completer, this.builder });
final Completer completer; final Completer completer;
final RouteBuilder builder; final RouteBuilder builder;
Duration get transitionDuration => _kTransitionDuration;
bool get opaque => false; bool get opaque => false;
Duration get transitionDuration => const Duration(milliseconds: 150);
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) { Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
return new FadeTransition( return new FadeTransition(
performance: performance, performance: performance,
...@@ -157,7 +156,7 @@ class DialogRoute extends Route { ...@@ -157,7 +156,7 @@ class DialogRoute extends Route {
Future showDialog(NavigatorState navigator, DialogBuilder builder) { Future showDialog(NavigatorState navigator, DialogBuilder builder) {
Completer completer = new Completer(); Completer completer = new Completer();
navigator.push(new DialogRoute( navigator.push(new _DialogRoute(
completer: completer, completer: completer,
builder: (RouteArguments args) { builder: (RouteArguments args) {
return new Focus( return new Focus(
......
...@@ -39,15 +39,15 @@ class Dismissable extends StatefulComponent { ...@@ -39,15 +39,15 @@ class Dismissable extends StatefulComponent {
this.direction: DismissDirection.horizontal this.direction: DismissDirection.horizontal
}) : super(key: key); }) : super(key: key);
Widget child; final Widget child;
ResizedCallback onResized; final ResizedCallback onResized;
DismissedCallback onDismissed; final DismissedCallback onDismissed;
DismissDirection direction; final DismissDirection direction;
DismissableState createState() => new DismissableState(); _DismissableState createState() => new _DismissableState();
} }
class DismissableState extends State<Dismissable> { class _DismissableState extends State<Dismissable> {
void initState() { void initState() {
super.initState(); super.initState();
_fadePerformance = new Performance(duration: _kCardDismissFadeout); _fadePerformance = new Performance(duration: _kCardDismissFadeout);
......
...@@ -62,10 +62,10 @@ class Draggable extends StatefulComponent { ...@@ -62,10 +62,10 @@ class Draggable extends StatefulComponent {
final Offset feedbackOffset; final Offset feedbackOffset;
final DragAnchor dragAnchor; final DragAnchor dragAnchor;
DraggableState createState() => new DraggableState(); _DraggableState createState() => new _DraggableState();
} }
class DraggableState extends State<Draggable> { class _DraggableState extends State<Draggable> {
DragRoute _route; DragRoute _route;
void _startDrag(sky.PointerEvent event) { void _startDrag(sky.PointerEvent event) {
......
...@@ -23,10 +23,10 @@ class DrawerItem extends StatefulComponent { ...@@ -23,10 +23,10 @@ class DrawerItem extends StatefulComponent {
final GestureTapCallback onPressed; final GestureTapCallback onPressed;
final bool selected; final bool selected;
DrawerItemState createState() => new DrawerItemState(); _DrawerItemState createState() => new _DrawerItemState();
} }
class DrawerItemState extends ButtonState<DrawerItem> { class _DrawerItemState extends ButtonState<DrawerItem> {
TextStyle _getTextStyle(ThemeData themeData) { TextStyle _getTextStyle(ThemeData themeData) {
TextStyle result = themeData.text.body2; TextStyle result = themeData.text.body2;
if (config.selected) if (config.selected)
......
...@@ -20,10 +20,10 @@ class FlatButton extends MaterialButton { ...@@ -20,10 +20,10 @@ class FlatButton extends MaterialButton {
enabled: enabled, enabled: enabled,
onPressed: onPressed); onPressed: onPressed);
FlatButtonState createState() => new FlatButtonState(); _FlatButtonState createState() => new _FlatButtonState();
} }
class FlatButtonState extends MaterialButtonState<FlatButton> { class _FlatButtonState extends MaterialButtonState<FlatButton> {
Color getColor(BuildContext context) { Color getColor(BuildContext context) {
if (!config.enabled || !highlight) if (!config.enabled || !highlight)
return null; return null;
......
...@@ -27,10 +27,10 @@ class FloatingActionButton extends StatefulComponent { ...@@ -27,10 +27,10 @@ class FloatingActionButton extends StatefulComponent {
final Color backgroundColor; final Color backgroundColor;
final GestureTapCallback onPressed; final GestureTapCallback onPressed;
FloatingActionButtonState createState() => new FloatingActionButtonState(); _FloatingActionButtonState createState() => new _FloatingActionButtonState();
} }
class FloatingActionButtonState extends ButtonState<FloatingActionButton> { class _FloatingActionButtonState extends ButtonState<FloatingActionButton> {
Widget buildContent(BuildContext context) { Widget buildContent(BuildContext context) {
IconThemeColor iconThemeColor = IconThemeColor.white; IconThemeColor iconThemeColor = IconThemeColor.white;
Color materialColor = config.backgroundColor; Color materialColor = config.backgroundColor;
......
...@@ -75,6 +75,52 @@ class Focus extends StatefulComponent { ...@@ -75,6 +75,52 @@ class Focus extends StatefulComponent {
final bool autofocus; final bool autofocus;
final Widget child; final Widget child;
static bool at(BuildContext context, Widget widget, { bool autofocus: true }) {
assert(widget != null);
assert(widget.key is GlobalKey);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null) {
if (autofocus)
focusScope._setFocusedWidgetIfUnset(widget.key);
return focusScope.scopeFocused &&
focusScope.focusedScope == null &&
focusScope.focusedWidget == widget.key;
}
return true;
}
static bool _atScope(BuildContext context, Widget widget, { bool autofocus: true }) {
assert(widget != null);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null) {
if (autofocus)
focusScope._setFocusedScopeIfUnset(widget.key);
assert(widget.key != null);
return focusScope.scopeFocused &&
focusScope.focusedScope == widget.key;
}
return true;
}
// Don't call moveTo() from your build() function, it's intended to be called
// from event listeners, e.g. in response to a finger tap or tab key.
static void moveTo(BuildContext context, Widget widget) {
assert(widget != null);
assert(widget.key is GlobalKey);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null)
focusScope.focusState._setFocusedWidget(widget.key);
}
static void _moveScopeTo(BuildContext context, Focus component) {
assert(component != null);
assert(component.key != null);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null)
focusScope.focusState._setFocusedScope(component.key);
}
FocusState createState() => new FocusState(); FocusState createState() => new FocusState();
} }
...@@ -155,7 +201,7 @@ class FocusState extends State<Focus> { ...@@ -155,7 +201,7 @@ class FocusState extends State<Focus> {
void initState() { void initState() {
super.initState(); super.initState();
if (config.autofocus) if (config.autofocus)
FocusState._moveScopeTo(context, config); Focus._moveScopeTo(context, config);
_updateWidgetRemovalListener(_focusedWidget); _updateWidgetRemovalListener(_focusedWidget);
_updateScopeRemovalListener(_focusedScope); _updateScopeRemovalListener(_focusedScope);
} }
...@@ -169,56 +215,10 @@ class FocusState extends State<Focus> { ...@@ -169,56 +215,10 @@ class FocusState extends State<Focus> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new _FocusScope( return new _FocusScope(
focusState: this, focusState: this,
scopeFocused: FocusState._atScope(context, config), scopeFocused: Focus._atScope(context, config),
focusedScope: _focusedScope == _noFocusedScope ? null : _focusedScope, focusedScope: _focusedScope == _noFocusedScope ? null : _focusedScope,
focusedWidget: _focusedWidget, focusedWidget: _focusedWidget,
child: config.child child: config.child
); );
} }
static bool at(BuildContext context, Widget widget, { bool autofocus: true }) {
assert(widget != null);
assert(widget.key is GlobalKey);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null) {
if (autofocus)
focusScope._setFocusedWidgetIfUnset(widget.key);
return focusScope.scopeFocused &&
focusScope.focusedScope == null &&
focusScope.focusedWidget == widget.key;
}
return true;
}
static bool _atScope(BuildContext context, Widget widget, { bool autofocus: true }) {
assert(widget != null);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null) {
if (autofocus)
focusScope._setFocusedScopeIfUnset(widget.key);
assert(widget.key != null);
return focusScope.scopeFocused &&
focusScope.focusedScope == widget.key;
}
return true;
}
// Don't call moveTo() from your build() function, it's intended to be called
// from event listeners, e.g. in response to a finger tap or tab key.
static void moveTo(BuildContext context, Widget widget) {
assert(widget != null);
assert(widget.key is GlobalKey);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null)
focusScope.focusState._setFocusedWidget(widget.key);
}
static void _moveScopeTo(BuildContext context, Focus component) {
assert(component != null);
assert(component.key != null);
_FocusScope focusScope = context.inheritedWidgetOfType(_FocusScope);
if (focusScope != null)
focusScope.focusState._setFocusedScope(component.key);
}
} }
...@@ -50,7 +50,7 @@ typedef void GlobalKeyRemoveListener(GlobalKey key); ...@@ -50,7 +50,7 @@ typedef void GlobalKeyRemoveListener(GlobalKey key);
/// A GlobalKey is one that must be unique across the entire application. It is /// A GlobalKey is one that must be unique across the entire application. It is
/// used by components that need to communicate with other components across the /// used by components that need to communicate with other components across the
/// application's element tree. /// application's element tree.
abstract class GlobalKey extends Key { abstract class GlobalKey<T extends State> extends Key {
const GlobalKey.constructor() : super.constructor(); // so that subclasses can call us, since the Key() factory constructor shadows the implicit constructor const GlobalKey.constructor() : super.constructor(); // so that subclasses can call us, since the Key() factory constructor shadows the implicit constructor
/// Constructs a LabeledGlobalKey, which is a GlobalKey with a label used for debugging. /// Constructs a LabeledGlobalKey, which is a GlobalKey with a label used for debugging.
...@@ -96,9 +96,9 @@ abstract class GlobalKey extends Key { ...@@ -96,9 +96,9 @@ abstract class GlobalKey extends Key {
Element get _currentElement => _registry[this]; Element get _currentElement => _registry[this];
BuildContext get currentContext => _currentElement; BuildContext get currentContext => _currentElement;
Widget get currentWidget => _currentElement?.widget; Widget get currentWidget => _currentElement?.widget;
State get currentState { T get currentState {
Element element = _currentElement; Element element = _currentElement;
if (element is StatefulComponentElement) if (element is StatefulComponentElement<dynamic, T>)
return element.state; return element.state;
return null; return null;
} }
...@@ -186,8 +186,8 @@ abstract class Widget { ...@@ -186,8 +186,8 @@ abstract class Widget {
final List<String> data = <String>[]; final List<String> data = <String>[];
debugFillDescription(data); debugFillDescription(data);
if (data.isEmpty) if (data.isEmpty)
return 'name'; return '$name';
return 'name(${data.join("; ")})'; return '$name(${data.join("; ")})';
} }
void debugFillDescription(List<String> description) { } void debugFillDescription(List<String> description) { }
...@@ -550,7 +550,7 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -550,7 +550,7 @@ abstract class Element<T extends Widget> implements BuildContext {
/// Wrapper around visitChildren for BuildContext. /// Wrapper around visitChildren for BuildContext.
void visitChildElements(void visitor(Element element)) { void visitChildElements(void visitor(Element element)) {
// don't allow visitChildElements() during build, since children aren't necessarily built yet // don't allow visitChildElements() during build, since children aren't necessarily built yet
assert(BuildableElement._debugStateLockLevel == 0); assert(!BuildableElement._debugStateLocked);
visitChildren(visitor); visitChildren(visitor);
} }
...@@ -858,6 +858,8 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -858,6 +858,8 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
assert(_child != null); assert(_child != null);
} }
static BuildableElement _debugCurrentBuildTarget;
/// Reinvokes the build() method of the StatelessComponent object (for /// Reinvokes the build() method of the StatelessComponent object (for
/// stateless components) or the State object (for stateful components) and /// stateless components) or the State object (for stateful components) and
/// then updates the widget tree. /// then updates the widget tree.
...@@ -874,6 +876,12 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -874,6 +876,12 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
assert(_debugLifecycleState == _ElementLifecycle.active); assert(_debugLifecycleState == _ElementLifecycle.active);
assert(_debugStateLocked); assert(_debugStateLocked);
assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true)); assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
BuildableElement debugPreviousBuildTarget;
assert(() {
debugPreviousBuildTarget = _debugCurrentBuildTarget;
_debugCurrentBuildTarget = this;
return true;
});
Widget built; Widget built;
try { try {
built = _builder(this); built = _builder(this);
...@@ -896,12 +904,19 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -896,12 +904,19 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
built = new ErrorWidget(); built = new ErrorWidget();
_child = updateChild(null, built, slot); _child = updateChild(null, built, slot);
} }
assert(() {
assert(_debugCurrentBuildTarget == this);
_debugCurrentBuildTarget = debugPreviousBuildTarget;
return true;
});
} }
static BuildScheduler scheduleBuildFor; static BuildScheduler scheduleBuildFor;
static int _debugStateLockLevel = 0; static int _debugStateLockLevel = 0;
static bool get _debugStateLocked => _debugStateLockLevel > 0; static bool get _debugStateLocked => _debugStateLockLevel > 0;
static bool _debugBuilding = false;
/// Establishes a scope in which component build functions can run. /// Establishes a scope in which component build functions can run.
/// ///
...@@ -913,13 +928,31 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -913,13 +928,31 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
/// After unwinding the last build scope on the stack, the framework verifies /// After unwinding the last build scope on the stack, the framework verifies
/// that each global key is used at most once and notifies listeners about /// that each global key is used at most once and notifies listeners about
/// changes to global keys. /// changes to global keys.
static void lockState(void callback()) { static void lockState(void callback(), { bool building: false }) {
_debugStateLockLevel += 1; assert(_debugStateLockLevel >= 0);
assert(() {
if (building) {
assert(!_debugBuilding);
assert(_debugCurrentBuildTarget == null);
_debugBuilding = true;
}
_debugStateLockLevel += 1;
return true;
});
try { try {
callback(); callback();
} finally { } finally {
_debugStateLockLevel -= 1; assert(() {
_debugStateLockLevel -= 1;
if (building) {
assert(_debugBuilding);
assert(_debugCurrentBuildTarget == null);
_debugBuilding = false;
}
return true;
});
} }
assert(_debugStateLockLevel >= 0);
} }
/// Marks the element as dirty and adds it to the global list of widgets to /// Marks the element as dirty and adds it to the global list of widgets to
...@@ -934,10 +967,23 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -934,10 +967,23 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
if (!_active) if (!_active)
return; return;
assert(_debugLifecycleState == _ElementLifecycle.active); assert(_debugLifecycleState == _ElementLifecycle.active);
assert(!_debugStateLocked || (_debugAllowIgnoredCallsToMarkNeedsBuild && dirty)); assert(() {
if (_debugBuilding) {
bool foundTarget = false;
visitAncestorElements((Element element) {
if (element == _debugCurrentBuildTarget) {
foundTarget = true;
return false;
}
return true;
});
if (foundTarget)
return true;
}
return !_debugStateLocked || (_debugAllowIgnoredCallsToMarkNeedsBuild && dirty);
});
if (dirty) if (dirty)
return; return;
assert(!_debugStateLocked);
_dirty = true; _dirty = true;
assert(scheduleBuildFor != null); assert(scheduleBuildFor != null);
scheduleBuildFor(this); scheduleBuildFor(this);
...@@ -1101,11 +1147,12 @@ class InheritedElement extends StatelessComponentElement<InheritedWidget> { ...@@ -1101,11 +1147,12 @@ class InheritedElement extends StatelessComponentElement<InheritedWidget> {
} }
void _notifyDescendants() { void _notifyDescendants() {
final Type ourRuntimeType = runtimeType; final Type ourRuntimeType = widget.runtimeType;
void notifyChildren(Element child) { void notifyChildren(Element child) {
if (child._dependencies != null && if (child._dependencies != null &&
child._dependencies.contains(ourRuntimeType)) child._dependencies.contains(ourRuntimeType)) {
child.dependenciesChanged(); child.dependenciesChanged();
}
if (child.runtimeType != ourRuntimeType) if (child.runtimeType != ourRuntimeType)
child.visitChildren(notifyChildren); child.visitChildren(notifyChildren);
} }
......
...@@ -59,10 +59,10 @@ class GestureDetector extends StatefulComponent { ...@@ -59,10 +59,10 @@ class GestureDetector extends StatefulComponent {
final GestureScaleUpdateCallback onScaleUpdate; final GestureScaleUpdateCallback onScaleUpdate;
final GestureScaleEndCallback onScaleEnd; final GestureScaleEndCallback onScaleEnd;
GestureDetectorState createState() => new GestureDetectorState(); _GestureDetectorState createState() => new _GestureDetectorState();
} }
class GestureDetectorState extends State<GestureDetector> { class _GestureDetectorState extends State<GestureDetector> {
final PointerRouter _router = FlutterBinding.instance.pointerRouter; final PointerRouter _router = FlutterBinding.instance.pointerRouter;
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
......
...@@ -30,7 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -30,7 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget {
final ScrollDirection direction; final ScrollDirection direction;
final double startOffset; final double startOffset;
HomogeneousViewportElement createElement() => new HomogeneousViewportElement(this); _HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this);
// we don't pass constructor arguments to the RenderBlockViewport() because until // we don't pass constructor arguments to the RenderBlockViewport() because until
// we know our children, the constructor arguments we could give have no effect // we know our children, the constructor arguments we could give have no effect
...@@ -48,8 +48,8 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -48,8 +48,8 @@ class HomogeneousViewport extends RenderObjectWidget {
// all the actual work is done in the element // all the actual work is done in the element
} }
class HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewport> { class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewport> {
HomogeneousViewportElement(HomogeneousViewport widget) : super(widget); _HomogeneousViewportElement(HomogeneousViewport widget) : super(widget);
List<Element> _children = const <Element>[]; List<Element> _children = const <Element>[];
int _layoutFirstIndex; int _layoutFirstIndex;
......
...@@ -61,7 +61,7 @@ class Icon extends StatelessComponent { ...@@ -61,7 +61,7 @@ class Icon extends StatelessComponent {
final IconThemeColor color; final IconThemeColor color;
final sky.ColorFilter colorFilter; final sky.ColorFilter colorFilter;
String getColorSuffix(BuildContext context) { String _getColorSuffix(BuildContext context) {
IconThemeColor iconThemeColor = color; IconThemeColor iconThemeColor = color;
if (iconThemeColor == null) { if (iconThemeColor == null) {
IconThemeData iconThemeData = IconTheme.of(context); IconThemeData iconThemeData = IconTheme.of(context);
...@@ -90,7 +90,7 @@ class Icon extends StatelessComponent { ...@@ -90,7 +90,7 @@ class Icon extends StatelessComponent {
// TODO(eseidel): This clearly isn't correct. Not sure what would be. // TODO(eseidel): This clearly isn't correct. Not sure what would be.
// Should we use the ios images on ios? // Should we use the ios images on ios?
String density = 'drawable-xxhdpi'; String density = 'drawable-xxhdpi';
String colorSuffix = getColorSuffix(context); String colorSuffix = _getColorSuffix(context);
return new AssetImage( return new AssetImage(
bundle: _iconBundle, bundle: _iconBundle,
name: '${category}/${density}/ic_${subtype}_${colorSuffix}_${size}dp.png', name: '${category}/${density}/ic_${subtype}_${colorSuffix}_${size}dp.png',
......
...@@ -26,8 +26,8 @@ double _getSplashTargetSize(Size bounds, Point position) { ...@@ -26,8 +26,8 @@ double _getSplashTargetSize(Size bounds, Point position) {
return math.max(math.max(d1, d2), math.max(d3, d4)).ceil().toDouble(); return math.max(math.max(d1, d2), math.max(d3, d4)).ceil().toDouble();
} }
class InkSplash { class _InkSplash {
InkSplash(this.position, this.well) { _InkSplash(this.position, this.well) {
_targetRadius = _getSplashTargetSize(well.size, position); _targetRadius = _getSplashTargetSize(well.size, position);
_radius = new AnimatedValue<double>( _radius = new AnimatedValue<double>(
_kSplashInitialSize, end: _targetRadius, curve: easeOut); _kSplashInitialSize, end: _targetRadius, curve: easeOut);
...@@ -42,7 +42,7 @@ class InkSplash { ...@@ -42,7 +42,7 @@ class InkSplash {
} }
final Point position; final Point position;
final RenderInkWell well; final _RenderInkWell well;
double _targetRadius; double _targetRadius;
double _pinnedRadius; double _pinnedRadius;
...@@ -98,8 +98,8 @@ class InkSplash { ...@@ -98,8 +98,8 @@ class InkSplash {
} }
} }
class RenderInkWell extends RenderProxyBox { class _RenderInkWell extends RenderProxyBox {
RenderInkWell({ _RenderInkWell({
RenderBox child, RenderBox child,
GestureTapCallback onTap, GestureTapCallback onTap,
GestureLongPressCallback onLongPress GestureLongPressCallback onLongPress
...@@ -122,7 +122,7 @@ class RenderInkWell extends RenderProxyBox { ...@@ -122,7 +122,7 @@ class RenderInkWell extends RenderProxyBox {
_syncLongPressRecognizer(); _syncLongPressRecognizer();
} }
final List<InkSplash> _splashes = new List<InkSplash>(); final List<_InkSplash> _splashes = new List<_InkSplash>();
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
LongPressGestureRecognizer _longPress; LongPressGestureRecognizer _longPress;
...@@ -131,7 +131,7 @@ class RenderInkWell extends RenderProxyBox { ...@@ -131,7 +131,7 @@ class RenderInkWell extends RenderProxyBox {
if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) { if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) {
_tap?.addPointer(event); _tap?.addPointer(event);
_longPress?.addPointer(event); _longPress?.addPointer(event);
_splashes.add(new InkSplash(entry.localPosition, this)); _splashes.add(new _InkSplash(entry.localPosition, this));
} }
} }
...@@ -196,7 +196,7 @@ class RenderInkWell extends RenderProxyBox { ...@@ -196,7 +196,7 @@ class RenderInkWell extends RenderProxyBox {
canvas.save(); canvas.save();
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
canvas.clipRect(Point.origin & size); canvas.clipRect(Point.origin & size);
for (InkSplash splash in _splashes) for (_InkSplash splash in _splashes)
splash.paint(canvas); splash.paint(canvas);
canvas.restore(); canvas.restore();
} }
...@@ -215,9 +215,9 @@ class InkWell extends OneChildRenderObjectWidget { ...@@ -215,9 +215,9 @@ class InkWell extends OneChildRenderObjectWidget {
final GestureTapCallback onTap; final GestureTapCallback onTap;
final GestureLongPressCallback onLongPress; final GestureLongPressCallback onLongPress;
RenderInkWell createRenderObject() => new RenderInkWell(onTap: onTap, onLongPress: onLongPress); _RenderInkWell createRenderObject() => new _RenderInkWell(onTap: onTap, onLongPress: onLongPress);
void updateRenderObject(RenderInkWell renderObject, InkWell oldWidget) { void updateRenderObject(_RenderInkWell renderObject, InkWell oldWidget) {
renderObject.onTap = onTap; renderObject.onTap = onTap;
renderObject.onLongPress = onLongPress; renderObject.onLongPress = onLongPress;
} }
......
...@@ -39,10 +39,10 @@ class Input extends Scrollable { ...@@ -39,10 +39,10 @@ class Input extends Scrollable {
final String placeholder; final String placeholder;
final StringValueChanged onChanged; final StringValueChanged onChanged;
InputState createState() => new InputState(); _InputState createState() => new _InputState();
} }
class InputState extends ScrollableState<Input> { class _InputState extends ScrollableState<Input> {
String _value; String _value;
EditableString _editableValue; EditableString _editableValue;
KeyboardHandle _keyboardHandle = KeyboardHandle.unattached; KeyboardHandle _keyboardHandle = KeyboardHandle.unattached;
...@@ -71,7 +71,7 @@ class InputState extends ScrollableState<Input> { ...@@ -71,7 +71,7 @@ class InputState extends ScrollableState<Input> {
Widget buildContent(BuildContext context) { Widget buildContent(BuildContext context) {
ThemeData themeData = Theme.of(context); ThemeData themeData = Theme.of(context);
bool focused = FocusState.at(context, config); bool focused = Focus.at(context, config);
if (focused && !_keyboardHandle.attached) { if (focused && !_keyboardHandle.attached) {
_keyboardHandle = keyboard.show(_editableValue.stub, config.keyboardType); _keyboardHandle = keyboard.show(_editableValue.stub, config.keyboardType);
...@@ -122,11 +122,11 @@ class InputState extends ScrollableState<Input> { ...@@ -122,11 +122,11 @@ class InputState extends ScrollableState<Input> {
) )
), ),
onPointerDown: (_) { onPointerDown: (_) {
if (FocusState.at(context, config)) { if (Focus.at(context, config)) {
assert(_keyboardHandle.attached); assert(_keyboardHandle.attached);
_keyboardHandle.showByRequest(); _keyboardHandle.showByRequest();
} else { } else {
FocusState.moveTo(context, config); Focus.moveTo(context, config);
// we'll get told to rebuild and we'll take care of the keyboard then // we'll get told to rebuild and we'll take care of the keyboard then
} }
} }
......
...@@ -12,7 +12,7 @@ import 'package:sky/src/widgets/theme.dart'; ...@@ -12,7 +12,7 @@ import 'package:sky/src/widgets/theme.dart';
enum MaterialType { canvas, card, circle, button } enum MaterialType { canvas, card, circle, button }
const Map<MaterialType, double> edges = const { const Map<MaterialType, double> _kEdges = const <MaterialType, double>{
MaterialType.canvas: null, MaterialType.canvas: null,
MaterialType.card: 2.0, MaterialType.card: 2.0,
MaterialType.circle: null, MaterialType.circle: null,
...@@ -35,7 +35,7 @@ class Material extends StatelessComponent { ...@@ -35,7 +35,7 @@ class Material extends StatelessComponent {
final int level; final int level;
final Color color; final Color color;
Color getBackgroundColor(BuildContext context) { Color _getBackgroundColor(BuildContext context) {
if (color != null) if (color != null)
return color; return color;
switch (type) { switch (type) {
...@@ -55,10 +55,10 @@ class Material extends StatelessComponent { ...@@ -55,10 +55,10 @@ class Material extends StatelessComponent {
style: Theme.of(context).text.body1, style: Theme.of(context).text.body1,
child: contents child: contents
); );
if (edges[type] != null) { if (_kEdges[type] != null) {
contents = new ClipRRect( contents = new ClipRRect(
xRadius: edges[type], xRadius: _kEdges[type],
yRadius: edges[type], yRadius: _kEdges[type],
child: contents child: contents
); );
} }
...@@ -67,10 +67,10 @@ class Material extends StatelessComponent { ...@@ -67,10 +67,10 @@ class Material extends StatelessComponent {
style: Theme.of(context).text.body1, style: Theme.of(context).text.body1,
child: new AnimatedContainer( child: new AnimatedContainer(
curve: ease, curve: ease,
duration: const Duration(milliseconds: 200), duration: kThemeChangeDuration,
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundColor: getBackgroundColor(context), backgroundColor: _getBackgroundColor(context),
borderRadius: edges[type], borderRadius: _kEdges[type],
boxShadow: level == 0 ? null : shadows[level], boxShadow: level == 0 ? null : shadows[level],
shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle
), ),
......
...@@ -9,7 +9,7 @@ import 'package:sky/src/widgets/framework.dart'; ...@@ -9,7 +9,7 @@ import 'package:sky/src/widgets/framework.dart';
import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/ink_well.dart';
import 'package:sky/src/widgets/material.dart'; import 'package:sky/src/widgets/material.dart';
// Rather than using this class directly, please use FlatButton or RaisedButton. /// Rather than using this class directly, please use FlatButton or RaisedButton.
abstract class MaterialButton extends StatefulComponent { abstract class MaterialButton extends StatefulComponent {
MaterialButton({ MaterialButton({
Key key, Key key,
......
...@@ -31,7 +31,7 @@ class MixedViewport extends RenderObjectWidget { ...@@ -31,7 +31,7 @@ class MixedViewport extends RenderObjectWidget {
final ExtentsUpdateCallback onExtentsUpdate; final ExtentsUpdateCallback onExtentsUpdate;
final InvalidatorAvailableCallback onInvalidatorAvailable; final InvalidatorAvailableCallback onInvalidatorAvailable;
MixedViewportElement createElement() => new MixedViewportElement(this); _MixedViewportElement createElement() => new _MixedViewportElement(this);
// we don't pass constructor arguments to the RenderBlockViewport() because until // we don't pass constructor arguments to the RenderBlockViewport() because until
// we know our children, the constructor arguments we could give have no effect // we know our children, the constructor arguments we could give have no effect
...@@ -60,8 +60,8 @@ class _ChildKey { ...@@ -60,8 +60,8 @@ class _ChildKey {
String toString() => "_ChildKey(type: $type, key: $key)"; String toString() => "_ChildKey(type: $type, key: $key)";
} }
class MixedViewportElement extends RenderObjectElement<MixedViewport> { class _MixedViewportElement extends RenderObjectElement<MixedViewport> {
MixedViewportElement(MixedViewport widget) : super(widget) { _MixedViewportElement(MixedViewport widget) : super(widget) {
if (widget.onInvalidatorAvailable != null) if (widget.onInvalidatorAvailable != null)
widget.onInvalidatorAvailable(invalidate); widget.onInvalidatorAvailable(invalidate);
} }
......
...@@ -18,7 +18,7 @@ class RouteArguments { ...@@ -18,7 +18,7 @@ class RouteArguments {
typedef Widget RouteBuilder(RouteArguments args); typedef Widget RouteBuilder(RouteArguments args);
typedef RouteBuilder RouteGenerator(String name); typedef RouteBuilder RouteGenerator(String name);
typedef void StateRouteCallback(StateRoute route); typedef void StateRouteCallback(StateRoute route);
typedef void NotificationCallback(); typedef void _RouteCallback(Route route);
class Navigator extends StatefulComponent { class Navigator extends StatefulComponent {
Navigator({ Navigator({
...@@ -51,7 +51,7 @@ class NavigatorState extends State<Navigator> { ...@@ -51,7 +51,7 @@ class NavigatorState extends State<Navigator> {
PageRoute route = new PageRoute(config.routes['/']); PageRoute route = new PageRoute(config.routes['/']);
assert(route != null); assert(route != null);
assert(!route.ephemeral); assert(!route.ephemeral);
_history.add(route); _insertRoute(route);
} }
void pushState(State owner, Function callback) { void pushState(State owner, Function callback) {
...@@ -63,29 +63,30 @@ class NavigatorState extends State<Navigator> { ...@@ -63,29 +63,30 @@ class NavigatorState extends State<Navigator> {
} }
void pushNamed(String name) { void pushNamed(String name) {
RouteBuilder builder; RouteBuilder generateRoute() {
if (!config.routes.containsKey(name)) {
assert(config.onGenerateRoute != null); assert(config.onGenerateRoute != null);
builder = config.onGenerateRoute(name); return config.onGenerateRoute(name);
} else {
builder = config.routes[name];
} }
if (builder == null) RouteBuilder builder = config.routes[name] ?? generateRoute() ?? config.onUnknownRoute;
builder = config.onUnknownRoute; // 404!
assert(builder != null); // 404 getting your 404!
push(new PageRoute(builder)); push(new PageRoute(builder));
} }
void _insertRoute(Route route) {
_history.insert(_currentPosition, route);
route._onDismissed = _handleRouteDismissed;
route._onRemoveRoute = _handleRemoveRoute;
route.didPush();
}
void push(Route route) { void push(Route route) {
assert(!_debugCurrentlyHaveRoute(route)); assert(!_debugCurrentlyHaveRoute(route));
setState(() { setState(() {
while (currentRoute.ephemeral) { while (currentRoute.ephemeral) {
assert(currentRoute.ephemeral);
currentRoute.didPop(null); currentRoute.didPop(null);
_currentPosition -= 1; _currentPosition -= 1;
} }
_history.insert(_currentPosition + 1, route);
_currentPosition += 1; _currentPosition += 1;
_insertRoute(route);
}); });
} }
...@@ -107,10 +108,6 @@ class NavigatorState extends State<Navigator> { ...@@ -107,10 +108,6 @@ class NavigatorState extends State<Navigator> {
void pop([dynamic result]) { void pop([dynamic result]) {
setState(() { setState(() {
while (currentRoute.ephemeral) {
currentRoute.didPop(null);
_currentPosition -= 1;
}
assert(_currentPosition > 0); assert(_currentPosition > 0);
currentRoute.didPop(result); currentRoute.didPop(result);
_currentPosition -= 1; _currentPosition -= 1;
...@@ -122,6 +119,19 @@ class NavigatorState extends State<Navigator> { ...@@ -122,6 +119,19 @@ class NavigatorState extends State<Navigator> {
return index >= 0 && index <= _currentPosition; return index >= 0 && index <= _currentPosition;
} }
void _handleRouteDismissed(Route route) {
assert(_history.contains(route));
if (_history.lastIndexOf(route) <= _currentPosition)
popRoute(route);
}
void _handleRemoveRoute(Route route) {
assert(_history.contains(route));
setState(() {
_history.remove(route);
});
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> visibleRoutes = new List<Widget>(); List<Widget> visibleRoutes = new List<Widget>();
bool alreadyInsertModalBarrier = false; bool alreadyInsertModalBarrier = false;
...@@ -132,20 +142,6 @@ class NavigatorState extends State<Navigator> { ...@@ -132,20 +142,6 @@ class NavigatorState extends State<Navigator> {
assert(!route.modal); assert(!route.modal);
continue; continue;
} }
route.ensurePerformance(
direction: (i <= _currentPosition) ? AnimationDirection.forward : AnimationDirection.reverse
);
route._onDismissed = () {
assert(_history.contains(route));
if (_history.lastIndexOf(route) <= _currentPosition)
popRoute(route);
};
route._onRemoveRoute = () {
assert(_history.contains(route));
setState(() {
_history.remove(route);
});
};
visibleRoutes.add( visibleRoutes.add(
new KeyedSubtree( new KeyedSubtree(
key: new ObjectKey(route), key: new ObjectKey(route),
...@@ -171,11 +167,14 @@ class NavigatorState extends State<Navigator> { ...@@ -171,11 +167,14 @@ class NavigatorState extends State<Navigator> {
abstract class Route { abstract class Route {
Route() {
_performance = createPerformance();
}
PerformanceView get performance => _performance?.view; PerformanceView get performance => _performance?.view;
Performance _performance; Performance _performance;
NotificationCallback _onDismissed; _RouteCallback _onDismissed;
NotificationCallback _onRemoveRoute; _RouteCallback _onRemoveRoute;
Performance createPerformance() { Performance createPerformance() {
Duration duration = transitionDuration; Duration duration = transitionDuration;
...@@ -184,26 +183,15 @@ abstract class Route { ...@@ -184,26 +183,15 @@ abstract class Route {
..addStatusListener((PerformanceStatus status) { ..addStatusListener((PerformanceStatus status) {
if (status == PerformanceStatus.dismissed) { if (status == PerformanceStatus.dismissed) {
if (_onDismissed != null) if (_onDismissed != null)
_onDismissed(); _onDismissed(this);
if (_onRemoveRoute != null) if (_onRemoveRoute != null)
_onRemoveRoute(); _onRemoveRoute(this);
} }
}); });
} }
return null; return null;
} }
void ensurePerformance({ AnimationDirection direction }) {
assert(direction != null);
if (_performance == null)
_performance = createPerformance();
if (_performance != null) {
PerformanceStatus desiredStatus = direction == AnimationDirection.forward ? PerformanceStatus.forward : PerformanceStatus.reverse;
if (_performance.status != desiredStatus)
_performance.play(direction);
}
}
/// If hasContent is true, then the route represents some on-screen state. /// If hasContent is true, then the route represents some on-screen state.
/// ///
/// If hasContent is false, then no performance will be created, and the values of /// If hasContent is false, then no performance will be created, and the values of
...@@ -262,9 +250,15 @@ abstract class Route { ...@@ -262,9 +250,15 @@ abstract class Route {
bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque; bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque;
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance); Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
void didPush() {
_performance?.forward();
}
void didPop([dynamic result]) { void didPop([dynamic result]) {
_performance?.reverse();
if (performance == null && _onRemoveRoute != null) if (performance == null && _onRemoveRoute != null)
_onRemoveRoute(); _onRemoveRoute(this);
} }
String toString() => '$runtimeType()'; String toString() => '$runtimeType()';
......
// 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/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart';
class Placeholder extends StatefulComponent {
Placeholder({ Key key }) : super(key: key);
PlaceholderState createState() => new PlaceholderState();
}
class PlaceholderState extends State<Placeholder> {
Widget get child => _child;
Widget _child;
void set child(Widget child) {
if (_child == child)
return;
setState(() {
_child = child;
});
}
Widget build(BuildContext context) {
if (_child != null)
return child;
return new SizedBox(width: 0.0, height: 0.0);
}
}
...@@ -21,7 +21,6 @@ import 'package:sky/src/widgets/transitions.dart'; ...@@ -21,7 +21,6 @@ import 'package:sky/src/widgets/transitions.dart';
const Duration _kMenuDuration = const Duration(milliseconds: 300); const Duration _kMenuDuration = const Duration(milliseconds: 300);
const double _kMenuCloseIntervalEnd = 2.0 / 3.0; const double _kMenuCloseIntervalEnd = 2.0 / 3.0;
const double _kMenuWidthStep = 56.0; const double _kMenuWidthStep = 56.0;
const double _kMenuMargin = 16.0; // 24.0 on tablet
const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
const double _kMenuHorizontalPadding = 16.0; const double _kMenuHorizontalPadding = 16.0;
...@@ -75,39 +74,36 @@ class PopupMenu extends StatelessComponent { ...@@ -75,39 +74,36 @@ class PopupMenu extends StatelessComponent {
return new FadeTransition( return new FadeTransition(
performance: performance, performance: performance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, 1.0 / 3.0)), opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: new Interval(0.0, 1.0 / 3.0)),
child: new Container( child: new BuilderTransition(
margin: new EdgeDims.all(_kMenuMargin), performance: performance,
child: new BuilderTransition( variables: [width, height],
performance: performance, builder: (BuildContext context) {
variables: [width, height], return new CustomPaint(
builder: (BuildContext context) { callback: (sky.Canvas canvas, Size size) {
return new CustomPaint( double widthValue = width.value * size.width;
callback: (sky.Canvas canvas, Size size) { double heightValue = height.value * size.height;
double widthValue = width.value * size.width; painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue));
double heightValue = height.value * size.height; },
painter.paint(canvas, new Rect.fromLTWH(size.width - widthValue, 0.0, widthValue, heightValue)); child: new ConstrainedBox(
}, constraints: new BoxConstraints(
child: new ConstrainedBox( minWidth: _kMenuMinWidth,
constraints: new BoxConstraints( maxWidth: _kMenuMaxWidth
minWidth: _kMenuMinWidth, ),
maxWidth: _kMenuMaxWidth child: new IntrinsicWidth(
), stepWidth: _kMenuWidthStep,
child: new IntrinsicWidth( child: new ScrollableViewport(
stepWidth: _kMenuWidthStep, child: new Container(
child: new ScrollableViewport( padding: const EdgeDims.symmetric(
child: new Container( horizontal: _kMenuHorizontalPadding,
padding: const EdgeDims.symmetric( vertical: _kMenuVerticalPadding
horizontal: _kMenuHorizontalPadding, ),
vertical: _kMenuVerticalPadding child: new BlockBody(children)
),
child: new BlockBody(children)
)
) )
) )
) )
); )
} );
) }
) )
); );
} }
...@@ -121,8 +117,8 @@ class MenuPosition { ...@@ -121,8 +117,8 @@ class MenuPosition {
final double left; final double left;
} }
class MenuRoute extends Route { class _MenuRoute extends Route {
MenuRoute({ this.completer, this.position, this.builder, this.level }); _MenuRoute({ this.completer, this.position, this.builder, this.level });
final Completer completer; final Completer completer;
final MenuPosition position; final MenuPosition position;
...@@ -137,7 +133,7 @@ class MenuRoute extends Route { ...@@ -137,7 +133,7 @@ class MenuRoute extends Route {
return result; return result;
} }
bool get ephemeral => false; // we could make this true, but then we'd have to use popRoute(), not pop(), in menus bool get ephemeral => true;
bool get modal => true; bool get modal => true;
bool get opaque => false; bool get opaque => false;
Duration get transitionDuration => _kMenuDuration; Duration get transitionDuration => _kMenuDuration;
...@@ -169,7 +165,7 @@ class MenuRoute extends Route { ...@@ -169,7 +165,7 @@ class MenuRoute extends Route {
Future showMenu({ NavigatorState navigator, MenuPosition position, PopupMenuItemsBuilder builder, int level: 4 }) { Future showMenu({ NavigatorState navigator, MenuPosition position, PopupMenuItemsBuilder builder, int level: 4 }) {
Completer completer = new Completer(); Completer completer = new Completer();
navigator.push(new MenuRoute( navigator.push(new _MenuRoute(
completer: completer, completer: completer,
position: position, position: position,
builder: builder, builder: builder,
......
...@@ -31,10 +31,10 @@ abstract class ProgressIndicator extends StatefulComponent { ...@@ -31,10 +31,10 @@ abstract class ProgressIndicator extends StatefulComponent {
Widget _buildIndicator(BuildContext context, double performanceValue); Widget _buildIndicator(BuildContext context, double performanceValue);
ProgressIndicatorState createState() => new ProgressIndicatorState(); _ProgressIndicatorState createState() => new _ProgressIndicatorState();
} }
class ProgressIndicatorState extends State<ProgressIndicator> { class _ProgressIndicatorState extends State<ProgressIndicator> {
ValuePerformance<double> _performance; ValuePerformance<double> _performance;
......
...@@ -14,7 +14,7 @@ const sky.Color _kDarkOffColor = const sky.Color(0xB2FFFFFF); ...@@ -14,7 +14,7 @@ const sky.Color _kDarkOffColor = const sky.Color(0xB2FFFFFF);
typedef RadioValueChanged(Object value); typedef RadioValueChanged(Object value);
class Radio extends StatefulComponent { class Radio extends StatelessComponent {
Radio({ Radio({
Key key, Key key,
this.value, this.value,
...@@ -28,13 +28,9 @@ class Radio extends StatefulComponent { ...@@ -28,13 +28,9 @@ class Radio extends StatefulComponent {
final Object groupValue; final Object groupValue;
final RadioValueChanged onChanged; final RadioValueChanged onChanged;
RadioState createState() => new RadioState();
}
class RadioState extends State<Radio> {
Color _getColor(BuildContext context) { Color _getColor(BuildContext context) {
ThemeData themeData = Theme.of(context); ThemeData themeData = Theme.of(context);
if (config.value == config.groupValue) if (value == groupValue)
return themeData.accentColor; return themeData.accentColor;
return themeData.brightness == ThemeBrightness.light ? _kLightOffColor : _kDarkOffColor; return themeData.brightness == ThemeBrightness.light ? _kLightOffColor : _kDarkOffColor;
} }
...@@ -44,7 +40,7 @@ class RadioState extends State<Radio> { ...@@ -44,7 +40,7 @@ class RadioState extends State<Radio> {
const double kOuterRadius = kDiameter / 2; const double kOuterRadius = kDiameter / 2;
const double kInnerRadius = 5.0; const double kInnerRadius = 5.0;
return new GestureDetector( return new GestureDetector(
onTap: () => config.onChanged(config.value), onTap: () => onChanged(value),
child: new Container( child: new Container(
margin: const EdgeDims.symmetric(horizontal: 5.0), margin: const EdgeDims.symmetric(horizontal: 5.0),
width: kDiameter, width: kDiameter,
...@@ -60,7 +56,7 @@ class RadioState extends State<Radio> { ...@@ -60,7 +56,7 @@ class RadioState extends State<Radio> {
canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kOuterRadius, paint); canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kOuterRadius, paint);
// Draw the inner circle // Draw the inner circle
if (config.value == config.groupValue) { if (value == groupValue) {
paint.setStyle(sky.PaintingStyle.fill); paint.setStyle(sky.PaintingStyle.fill);
canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kInnerRadius, paint); canvas.drawCircle(const Point(kOuterRadius, kOuterRadius), kInnerRadius, paint);
} }
......
...@@ -22,10 +22,10 @@ class RaisedButton extends MaterialButton { ...@@ -22,10 +22,10 @@ class RaisedButton extends MaterialButton {
assert(enabled != null); assert(enabled != null);
} }
RaisedButtonState createState() => new RaisedButtonState(); _RaisedButtonState createState() => new _RaisedButtonState();
} }
class RaisedButtonState extends MaterialButtonState<RaisedButton> { class _RaisedButtonState extends MaterialButtonState<RaisedButton> {
Color getColor(BuildContext context) { Color getColor(BuildContext context) {
if (config.enabled) { if (config.enabled) {
switch (Theme.of(context).brightness) { switch (Theme.of(context).brightness) {
......
...@@ -6,247 +6,88 @@ import 'dart:sky' as sky; ...@@ -6,247 +6,88 @@ import 'dart:sky' as sky;
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/rendering.dart'; import 'package:sky/rendering.dart';
import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart'; import 'package:sky/src/widgets/framework.dart';
// Slots are painted in this order and hit tested in reverse of this order class Scaffold extends StatelessComponent {
enum ScaffoldSlots { Scaffold({
body, Key key,
statusBar, this.body,
toolbar, this.statusBar,
snackBar, this.toolBar,
floatingActionButton, this.snackBar,
drawer this.floatingActionButton
} }) : super(key: key);
class RenderScaffold extends RenderBox { final Widget body;
final Widget statusBar;
RenderScaffold({ final Widget toolBar;
RenderBox body, final Widget snackBar;
RenderBox statusBar, final Widget floatingActionButton;
RenderBox toolbar,
RenderBox snackBar, Widget build(BuildContext context) {
RenderBox floatingActionButton, double toolBarHeight = 0.0;
RenderBox drawer if (toolBar != null)
}) { toolBarHeight = kToolBarHeight + sky.view.paddingTop;
this[ScaffoldSlots.body] = body;
this[ScaffoldSlots.statusBar] = statusBar; double statusBarHeight = 0.0;
this[ScaffoldSlots.toolbar] = toolbar; if (statusBar != null)
this[ScaffoldSlots.snackBar] = snackBar; statusBarHeight = kStatusBarHeight;
this[ScaffoldSlots.floatingActionButton] = floatingActionButton;
this[ScaffoldSlots.drawer] = drawer; List<Widget> children = <Widget>[];
}
if (body != null) {
Map<ScaffoldSlots, RenderBox> _slots = new Map<ScaffoldSlots, RenderBox>(); children.add(new Positioned(
RenderBox operator[] (ScaffoldSlots slot) => _slots[slot]; top: toolBarHeight, right: 0.0, bottom: statusBarHeight, left: 0.0,
void operator[]= (ScaffoldSlots slot, RenderBox value) { child: body
RenderBox old = _slots[slot]; ));
if (old == value) }
return;
if (old != null) if (statusBar != null) {
dropChild(old); children.add(new Positioned(
if (value == null) { right: 0.0, bottom: 0.0, left: 0.0,
_slots.remove(slot); child: new SizedBox(
} else { height: statusBarHeight,
_slots[slot] = value; child: statusBar
adoptChild(value); )
} ));
markNeedsLayout(); }
}
if (toolBar != null) {
void attachChildren() { children.add(new Positioned(
for (ScaffoldSlots slot in ScaffoldSlots.values) { top: 0.0, right: 0.0, left: 0.0,
RenderBox box = _slots[slot]; child: new SizedBox(
if (box != null) height: toolBarHeight,
box.attach(); child: toolBar
} )
} ));
}
void detachChildren() {
for (ScaffoldSlots slot in ScaffoldSlots.values) { if (snackBar != null || floatingActionButton != null) {
RenderBox box = _slots[slot]; List<Widget> floatingChildren = <Widget>[];
if (box != null)
box.detach(); if (floatingActionButton != null) {
} floatingChildren.add(new Padding(
} // TODO(eseidel): These change based on device size!
padding: const EdgeDims.only(right: 16.0, bottom: 16.0),
void visitChildren(RenderObjectVisitor visitor) { child: floatingActionButton
for (ScaffoldSlots slot in ScaffoldSlots.values) { ));
RenderBox box = _slots[slot];
if (box != null)
visitor(box);
}
}
ScaffoldSlots remove(RenderBox child) {
assert(child != null);
for (ScaffoldSlots slot in ScaffoldSlots.values) {
if (_slots[slot] == child) {
this[slot] = null;
return slot;
} }
}
return null;
}
bool get sizedByParent => true;
void performResize() {
size = constraints.biggest;
assert(!size.isInfinite);
}
// TODO(eseidel): These change based on device size!
// http://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
static const kButtonX = 16.0; // left from right edge of body
static const kButtonY = 16.0; // up from bottom edge of body
void performLayout() {
double bodyHeight = size.height;
double bodyPosition = 0.0;
double fabOffset = 0.0;
if (_slots[ScaffoldSlots.statusBar] != null) {
RenderBox statusBar = _slots[ScaffoldSlots.statusBar];
statusBar.layout(new BoxConstraints.tight(new Size(size.width, kStatusBarHeight)));
assert(statusBar.parentData is BoxParentData);
statusBar.parentData.position = new Point(0.0, size.height - kStatusBarHeight);
bodyHeight -= kStatusBarHeight;
}
if (_slots[ScaffoldSlots.toolbar] != null) {
RenderBox toolbar = _slots[ScaffoldSlots.toolbar];
double toolbarHeight = kToolBarHeight + sky.view.paddingTop;
toolbar.layout(new BoxConstraints.tight(new Size(size.width, toolbarHeight)));
assert(toolbar.parentData is BoxParentData);
toolbar.parentData.position = Point.origin;
bodyPosition += toolbarHeight;
bodyHeight -= toolbarHeight;
}
if (_slots[ScaffoldSlots.body] != null) {
RenderBox body = _slots[ScaffoldSlots.body];
body.layout(new BoxConstraints.tight(new Size(size.width, bodyHeight)));
assert(body.parentData is BoxParentData);
body.parentData.position = new Point(0.0, bodyPosition);
}
if (_slots[ScaffoldSlots.snackBar] != null) {
RenderBox snackBar = _slots[ScaffoldSlots.snackBar];
// TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568 // TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568
snackBar.layout( if (snackBar != null) {
new BoxConstraints(minWidth: size.width, maxWidth: size.width, minHeight: 0.0, maxHeight: bodyHeight), floatingChildren.add(new ConstrainedBox(
parentUsesSize: true constraints: const BoxConstraints(maxHeight: kSnackBarHeight),
); child: snackBar
assert(snackBar.parentData is BoxParentData); ));
snackBar.parentData.position = new Point(0.0, bodyPosition + bodyHeight - snackBar.size.height);
fabOffset += snackBar.size.height;
}
if (_slots[ScaffoldSlots.floatingActionButton] != null) {
RenderBox floatingActionButton = _slots[ScaffoldSlots.floatingActionButton];
Size area = new Size(size.width - kButtonX, size.height - kButtonY);
floatingActionButton.layout(new BoxConstraints.loose(area), parentUsesSize: true);
assert(floatingActionButton.parentData is BoxParentData);
floatingActionButton.parentData.position = (area - floatingActionButton.size).toPoint() + new Offset(0.0, -fabOffset);
}
if (_slots[ScaffoldSlots.drawer] != null) {
RenderBox drawer = _slots[ScaffoldSlots.drawer];
drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: size.width, minHeight: size.height, maxHeight: size.height));
assert(drawer.parentData is BoxParentData);
drawer.parentData.position = Point.origin;
}
}
void paint(PaintingContext context, Offset offset) {
for (ScaffoldSlots slot in ScaffoldSlots.values) {
RenderBox box = _slots[slot];
if (box != null) {
assert(box.parentData is BoxParentData);
context.paintChild(box, box.parentData.position + offset);
} }
}
}
void hitTestChildren(HitTestResult result, { Point position }) { children.add(new Positioned(
for (ScaffoldSlots slot in ScaffoldSlots.values.reversed) { right: 0.0, bottom: statusBarHeight, left: 0.0,
RenderBox box = _slots[slot]; child: new Column(floatingChildren, alignItems: FlexAlignItems.end)
if (box != null) { ));
assert(box.parentData is BoxParentData);
if (box.hitTest(result, position: (position - box.parentData.position).toPoint()))
return;
}
} }
}
String debugDescribeChildren(String prefix) {
return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toStringDeep(prefix)}').join();
}
}
class Scaffold extends RenderObjectWidget {
Scaffold({
Key key,
Widget body,
Widget statusBar,
Widget toolbar,
Widget snackBar,
Widget floatingActionButton,
Widget drawer
}) : super(key: key) {
_children[ScaffoldSlots.body] = body;
_children[ScaffoldSlots.statusBar] = statusBar;
_children[ScaffoldSlots.toolbar] = toolbar;
_children[ScaffoldSlots.snackBar] = snackBar;
_children[ScaffoldSlots.floatingActionButton] = floatingActionButton;
_children[ScaffoldSlots.drawer] = drawer;
}
final Map<ScaffoldSlots, Widget> _children = new Map<ScaffoldSlots, Widget>();
RenderScaffold createRenderObject() => new RenderScaffold();
ScaffoldElement createElement() => new ScaffoldElement(this);
}
class ScaffoldElement extends RenderObjectElement<Scaffold> {
ScaffoldElement(Scaffold widget) : super(widget);
Map<ScaffoldSlots, Element> _children;
RenderScaffold get renderObject => super.renderObject;
void visitChildren(ElementVisitor visitor) {
for (ScaffoldSlots slot in ScaffoldSlots.values) {
Element element = _children[slot];
if (element != null)
visitor(element);
}
}
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_children = new Map<ScaffoldSlots, Element>();
for (ScaffoldSlots slot in ScaffoldSlots.values) {
Element newChild = widget._children[slot]?.createElement();
_children[slot] = newChild;
newChild?.mount(this, slot);
}
}
void update(Scaffold newWidget) {
super.update(newWidget);
assert(widget == newWidget);
for (ScaffoldSlots slot in ScaffoldSlots.values) {
_children[slot] = updateChild(_children[slot], widget._children[slot], slot);
assert((_children[slot] == null) == (widget._children[slot] == null));
}
}
void insertChildRenderObject(RenderObject child, ScaffoldSlots slot) {
renderObject[slot] = child;
}
void moveChildRenderObject(RenderObject child, dynamic slot) {
removeChildRenderObject(child);
insertChildRenderObject(child, slot);
}
void removeChildRenderObject(RenderObject child) { return new Stack(children);
assert(renderObject == child.parent);
renderObject.remove(child);
} }
} }
...@@ -575,7 +575,7 @@ typedef void PageChangedCallback(int newPage); ...@@ -575,7 +575,7 @@ typedef void PageChangedCallback(int newPage);
class PageableList<T> extends ScrollableList<T> { class PageableList<T> extends ScrollableList<T> {
PageableList({ PageableList({
Key key, Key key,
double initialScrollOffset, int initialPage,
ScrollDirection scrollDirection: ScrollDirection.horizontal, ScrollDirection scrollDirection: ScrollDirection.horizontal,
ScrollListener onScroll, ScrollListener onScroll,
List<T> items, List<T> items,
...@@ -588,7 +588,7 @@ class PageableList<T> extends ScrollableList<T> { ...@@ -588,7 +588,7 @@ class PageableList<T> extends ScrollableList<T> {
this.curve: ease this.curve: ease
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialPage == null ? null : initialPage * itemExtent,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
onScroll: onScroll, onScroll: onScroll,
items: items, items: items,
......
...@@ -6,21 +6,18 @@ import 'package:sky/animation.dart'; ...@@ -6,21 +6,18 @@ import 'package:sky/animation.dart';
import 'package:sky/gestures.dart'; import 'package:sky/gestures.dart';
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/painting.dart'; import 'package:sky/painting.dart';
import 'package:sky/src/widgets/animated_component.dart';
import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart'; import 'package:sky/src/widgets/framework.dart';
import 'package:sky/src/widgets/gesture_detector.dart'; import 'package:sky/src/widgets/gesture_detector.dart';
import 'package:sky/src/widgets/material.dart'; import 'package:sky/src/widgets/material.dart';
import 'package:sky/src/widgets/navigator.dart';
import 'package:sky/src/widgets/placeholder.dart';
import 'package:sky/src/widgets/theme.dart'; import 'package:sky/src/widgets/theme.dart';
import 'package:sky/src/widgets/transitions.dart'; import 'package:sky/src/widgets/transitions.dart';
typedef void SnackBarDismissedCallback(); const double _kSideMargins = 24.0;
const double _kVerticalPadding = 14.0;
const Duration _kSlideInDuration = const Duration(milliseconds: 200); const Color _kSnackBackground = const Color(0xFF323232);
const double kSnackHeight = 52.0;
const double kSideMargins = 24.0;
const double kVerticalPadding = 14.0;
const Color kSnackBackground = const Color(0xFF323232);
class SnackBarAction extends StatelessComponent { class SnackBarAction extends StatelessComponent {
SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) { SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
...@@ -34,70 +31,60 @@ class SnackBarAction extends StatelessComponent { ...@@ -34,70 +31,60 @@ class SnackBarAction extends StatelessComponent {
return new GestureDetector( return new GestureDetector(
onTap: onPressed, onTap: onPressed,
child: new Container( child: new Container(
margin: const EdgeDims.only(left: kSideMargins), margin: const EdgeDims.only(left: _kSideMargins),
padding: const EdgeDims.symmetric(vertical: kVerticalPadding), padding: const EdgeDims.symmetric(vertical: _kVerticalPadding),
child: new Text(label) child: new Text(label)
) )
); );
} }
} }
class SnackBar extends AnimatedComponent { class SnackBar extends StatelessComponent {
SnackBar({ SnackBar({
Key key, Key key,
this.content, this.content,
this.actions, this.actions,
bool showing, this.performance
this.onDismissed }) : super(key: key) {
}) : super(key: key, direction: showing ? AnimationDirection.forward : AnimationDirection.reverse, duration: _kSlideInDuration) {
assert(content != null); assert(content != null);
} }
final Widget content; final Widget content;
final List<SnackBarAction> actions; final List<SnackBarAction> actions;
final SnackBarDismissedCallback onDismissed; final PerformanceView performance;
SnackBarState createState() => new SnackBarState();
}
class SnackBarState extends AnimatedState<SnackBar> {
void handleDismissed() {
if (config.onDismissed != null)
config.onDismissed();
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> children = [ List<Widget> children = [
new Flexible( new Flexible(
child: new Container( child: new Container(
margin: const EdgeDims.symmetric(vertical: kVerticalPadding), margin: const EdgeDims.symmetric(vertical: _kVerticalPadding),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: Typography.white.subhead, style: Typography.white.subhead,
child: config.content child: content
) )
) )
) )
]; ];
if (config.actions != null) if (actions != null)
children.addAll(config.actions); children.addAll(actions);
return new SquashTransition( return new SquashTransition(
performance: performance.view, performance: performance,
height: new AnimatedValue<double>( height: new AnimatedValue<double>(
0.0, 0.0,
end: kSnackHeight, end: kSnackBarHeight,
curve: easeIn, curve: easeIn,
reverseCurve: easeOut reverseCurve: easeOut
), ),
child: new ClipRect( child: new ClipRect(
child: new OverflowBox( child: new OverflowBox(
minHeight: kSnackHeight, minHeight: kSnackBarHeight,
maxHeight: kSnackHeight, maxHeight: kSnackBarHeight,
child: new Material( child: new Material(
level: 2, level: 2,
color: kSnackBackground, color: _kSnackBackground,
type: MaterialType.canvas, type: MaterialType.canvas,
child: new Container( child: new Container(
margin: const EdgeDims.symmetric(horizontal: kSideMargins), margin: const EdgeDims.symmetric(horizontal: _kSideMargins),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: new TextStyle(color: Theme.of(context).accentColor), style: new TextStyle(color: Theme.of(context).accentColor),
child: new Row(children) child: new Row(children)
...@@ -109,3 +96,28 @@ class SnackBarState extends AnimatedState<SnackBar> { ...@@ -109,3 +96,28 @@ class SnackBarState extends AnimatedState<SnackBar> {
); );
} }
} }
class _SnackBarRoute extends Route {
_SnackBarRoute({ this.content, this.actions });
final Widget content;
final List<SnackBarAction> actions;
bool get hasContent => false;
bool get ephemeral => true;
bool get modal => false;
Duration get transitionDuration => const Duration(milliseconds: 200);
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) => null;
}
void showSnackBar({ NavigatorState navigator, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
Route route = new _SnackBarRoute();
SnackBar snackBar = new SnackBar(
content: content,
actions: actions,
performance: route.performance
);
placeholderKey.currentState.child = snackBar;
navigator.push(route);
}
...@@ -11,6 +11,7 @@ import 'package:sky/gestures.dart'; ...@@ -11,6 +11,7 @@ import 'package:sky/gestures.dart';
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/painting.dart'; import 'package:sky/painting.dart';
import 'package:sky/rendering.dart'; import 'package:sky/rendering.dart';
import 'package:sky/src/widgets/animated_container.dart';
import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart'; import 'package:sky/src/widgets/framework.dart';
import 'package:sky/src/widgets/icon.dart'; import 'package:sky/src/widgets/icon.dart';
...@@ -19,8 +20,8 @@ import 'package:sky/src/widgets/scrollable.dart'; ...@@ -19,8 +20,8 @@ import 'package:sky/src/widgets/scrollable.dart';
import 'package:sky/src/widgets/theme.dart'; import 'package:sky/src/widgets/theme.dart';
import 'package:sky/src/widgets/transitions.dart'; import 'package:sky/src/widgets/transitions.dart';
typedef void SelectedIndexChanged(int selectedIndex); typedef void TabSelectedIndexChanged(int selectedIndex);
typedef void LayoutChanged(Size size, List<double> widths); typedef void TabLayoutChanged(Size size, List<double> widths);
// See https://www.google.com/design/spec/components/tabs.html#tabs-specs // See https://www.google.com/design/spec/components/tabs.html#tabs-specs
const double _kTabHeight = 46.0; const double _kTabHeight = 46.0;
...@@ -33,14 +34,14 @@ const int _kTabIconSize = 24; ...@@ -33,14 +34,14 @@ const int _kTabIconSize = 24;
const double _kTabBarScrollDrag = 0.025; const double _kTabBarScrollDrag = 0.025;
const Duration _kTabBarScroll = const Duration(milliseconds: 200); const Duration _kTabBarScroll = const Duration(milliseconds: 200);
class TabBarParentData extends BoxParentData with class _TabBarParentData extends BoxParentData with
ContainerParentDataMixin<RenderBox> { } ContainerParentDataMixin<RenderBox> { }
class RenderTabBar extends RenderBox with class _RenderTabBar extends RenderBox with
ContainerRenderObjectMixin<RenderBox, TabBarParentData>, ContainerRenderObjectMixin<RenderBox, _TabBarParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, TabBarParentData> { RenderBoxContainerDefaultsMixin<RenderBox, _TabBarParentData> {
RenderTabBar(this.onLayoutChanged); _RenderTabBar(this.onLayoutChanged);
int _selectedIndex; int _selectedIndex;
int get selectedIndex => _selectedIndex; int get selectedIndex => _selectedIndex;
...@@ -51,15 +52,6 @@ class RenderTabBar extends RenderBox with ...@@ -51,15 +52,6 @@ class RenderTabBar extends RenderBox with
} }
} }
Color _backgroundColor;
Color get backgroundColor => _backgroundColor;
void set backgroundColor(Color value) {
if (_backgroundColor != value) {
_backgroundColor = value;
markNeedsPaint();
}
}
Color _indicatorColor; Color _indicatorColor;
Color get indicatorColor => _indicatorColor; Color get indicatorColor => _indicatorColor;
void set indicatorColor(Color value) { void set indicatorColor(Color value) {
...@@ -97,8 +89,8 @@ class RenderTabBar extends RenderBox with ...@@ -97,8 +89,8 @@ class RenderTabBar extends RenderBox with
} }
void setupParentData(RenderBox child) { void setupParentData(RenderBox child) {
if (child.parentData is! TabBarParentData) if (child.parentData is! _TabBarParentData)
child.parentData = new TabBarParentData(); child.parentData = new _TabBarParentData();
} }
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(BoxConstraints constraints) {
...@@ -109,7 +101,7 @@ class RenderTabBar extends RenderBox with ...@@ -109,7 +101,7 @@ class RenderTabBar extends RenderBox with
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints)); maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints));
assert(child.parentData is TabBarParentData); assert(child.parentData is _TabBarParentData);
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
} }
double width = isScrollable ? maxWidth : maxWidth * childCount; double width = isScrollable ? maxWidth : maxWidth * childCount;
...@@ -124,7 +116,7 @@ class RenderTabBar extends RenderBox with ...@@ -124,7 +116,7 @@ class RenderTabBar extends RenderBox with
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints)); maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints));
assert(child.parentData is TabBarParentData); assert(child.parentData is _TabBarParentData);
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
} }
double width = isScrollable ? maxWidth : maxWidth * childCount; double width = isScrollable ? maxWidth : maxWidth * childCount;
...@@ -148,7 +140,7 @@ class RenderTabBar extends RenderBox with ...@@ -148,7 +140,7 @@ class RenderTabBar extends RenderBox with
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
child.layout(tabConstraints); child.layout(tabConstraints);
assert(child.parentData is TabBarParentData); assert(child.parentData is _TabBarParentData);
child.parentData.position = new Point(x, 0.0); child.parentData.position = new Point(x, 0.0);
x += tabWidth; x += tabWidth;
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
...@@ -166,7 +158,7 @@ class RenderTabBar extends RenderBox with ...@@ -166,7 +158,7 @@ class RenderTabBar extends RenderBox with
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
child.layout(tabConstraints, parentUsesSize: true); child.layout(tabConstraints, parentUsesSize: true);
assert(child.parentData is TabBarParentData); assert(child.parentData is _TabBarParentData);
child.parentData.position = new Point(x, 0.0); child.parentData.position = new Point(x, 0.0);
x += child.size.width; x += child.size.width;
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
...@@ -176,7 +168,7 @@ class RenderTabBar extends RenderBox with ...@@ -176,7 +168,7 @@ class RenderTabBar extends RenderBox with
Size layoutSize; Size layoutSize;
List<double> layoutWidths; List<double> layoutWidths;
LayoutChanged onLayoutChanged; TabLayoutChanged onLayoutChanged;
void reportLayoutChangedIfNeeded() { void reportLayoutChangedIfNeeded() {
assert(onLayoutChanged != null); assert(onLayoutChanged != null);
...@@ -240,17 +232,10 @@ class RenderTabBar extends RenderBox with ...@@ -240,17 +232,10 @@ class RenderTabBar extends RenderBox with
} }
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (backgroundColor != null) {
double width = layoutWidths != null
? layoutWidths.reduce((sum, width) => sum + width)
: size.width;
Rect rect = offset & new Size(width, size.height);
context.canvas.drawRect(rect, new Paint()..color = backgroundColor);
}
int index = 0; int index = 0;
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
assert(child.parentData is TabBarParentData); assert(child.parentData is _TabBarParentData);
context.paintChild(child, child.parentData.position + offset); context.paintChild(child, child.parentData.position + offset);
if (index++ == selectedIndex) if (index++ == selectedIndex)
_paintIndicator(context.canvas, child, offset); _paintIndicator(context.canvas, child, offset);
...@@ -264,7 +249,6 @@ class _TabBarWrapper extends MultiChildRenderObjectWidget { ...@@ -264,7 +249,6 @@ class _TabBarWrapper extends MultiChildRenderObjectWidget {
Key key, Key key,
List<Widget> children, List<Widget> children,
this.selectedIndex, this.selectedIndex,
this.backgroundColor,
this.indicatorColor, this.indicatorColor,
this.indicatorRect, this.indicatorRect,
this.textAndIcons, this.textAndIcons,
...@@ -273,22 +257,20 @@ class _TabBarWrapper extends MultiChildRenderObjectWidget { ...@@ -273,22 +257,20 @@ class _TabBarWrapper extends MultiChildRenderObjectWidget {
}) : super(key: key, children: children); }) : super(key: key, children: children);
final int selectedIndex; final int selectedIndex;
final Color backgroundColor;
final Color indicatorColor; final Color indicatorColor;
final Rect indicatorRect; final Rect indicatorRect;
final bool textAndIcons; final bool textAndIcons;
final bool isScrollable; final bool isScrollable;
final LayoutChanged onLayoutChanged; final TabLayoutChanged onLayoutChanged;
RenderTabBar createRenderObject() { _RenderTabBar createRenderObject() {
RenderTabBar result = new RenderTabBar(onLayoutChanged); _RenderTabBar result = new _RenderTabBar(onLayoutChanged);
updateRenderObject(result, null); updateRenderObject(result, null);
return result; return result;
} }
void updateRenderObject(RenderTabBar renderObject, _TabBarWrapper oldWidget) { void updateRenderObject(_RenderTabBar renderObject, _TabBarWrapper oldWidget) {
renderObject.selectedIndex = selectedIndex; renderObject.selectedIndex = selectedIndex;
renderObject.backgroundColor = backgroundColor;
renderObject.indicatorColor = indicatorColor; renderObject.indicatorColor = indicatorColor;
renderObject.indicatorRect = indicatorRect; renderObject.indicatorRect = indicatorRect;
renderObject.textAndIcons = textAndIcons; renderObject.textAndIcons = textAndIcons;
...@@ -399,13 +381,13 @@ class TabBar extends Scrollable { ...@@ -399,13 +381,13 @@ class TabBar extends Scrollable {
final Iterable<TabLabel> labels; final Iterable<TabLabel> labels;
final int selectedIndex; final int selectedIndex;
final SelectedIndexChanged onChanged; final TabSelectedIndexChanged onChanged;
final bool isScrollable; final bool isScrollable;
TabBarState createState() => new TabBarState(); _TabBarState createState() => new _TabBarState();
} }
class TabBarState extends ScrollableState<TabBar> { class _TabBarState extends ScrollableState<TabBar> {
void initState() { void initState() {
super.initState(); super.initState();
_indicatorAnimation = new ValuePerformance<Rect>() _indicatorAnimation = new ValuePerformance<Rect>()
...@@ -537,7 +519,7 @@ class TabBarState extends ScrollableState<TabBar> { ...@@ -537,7 +519,7 @@ class TabBarState extends ScrollableState<TabBar> {
textAndIcons = true; textAndIcons = true;
} }
Widget tabBar = new IconTheme( Widget content = new IconTheme(
data: new IconThemeData(color: iconThemeColor), data: new IconThemeData(color: iconThemeColor),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: textStyle, style: textStyle,
...@@ -548,7 +530,6 @@ class TabBarState extends ScrollableState<TabBar> { ...@@ -548,7 +530,6 @@ class TabBarState extends ScrollableState<TabBar> {
return new _TabBarWrapper( return new _TabBarWrapper(
children: tabs, children: tabs,
selectedIndex: config.selectedIndex, selectedIndex: config.selectedIndex,
backgroundColor: backgroundColor,
indicatorColor: indicatorColor, indicatorColor: indicatorColor,
indicatorRect: _indicatorRect.value, indicatorRect: _indicatorRect.value,
textAndIcons: textAndIcons, textAndIcons: textAndIcons,
...@@ -560,16 +541,23 @@ class TabBarState extends ScrollableState<TabBar> { ...@@ -560,16 +541,23 @@ class TabBarState extends ScrollableState<TabBar> {
) )
); );
if (!config.isScrollable) if (config.isScrollable) {
return tabBar; content = new SizeObserver(
callback: _handleViewportSizeChanged,
return new SizeObserver( child: new Viewport(
callback: _handleViewportSizeChanged, scrollDirection: ScrollDirection.horizontal,
child: new Viewport( scrollOffset: new Offset(scrollOffset, 0.0),
scrollDirection: ScrollDirection.horizontal, child: content
scrollOffset: new Offset(scrollOffset, 0.0), )
child: tabBar );
) }
return new AnimatedContainer(
decoration: new BoxDecoration(
backgroundColor: backgroundColor
),
duration: kThemeChangeDuration,
child: content
); );
} }
} }
...@@ -598,21 +586,16 @@ class TabNavigator extends StatelessComponent { ...@@ -598,21 +586,16 @@ class TabNavigator extends StatelessComponent {
final List<TabNavigatorView> views; final List<TabNavigatorView> views;
final int selectedIndex; final int selectedIndex;
final SelectedIndexChanged onChanged; final TabSelectedIndexChanged onChanged;
final bool isScrollable; final bool isScrollable;
void _handleSelectedIndexChanged(int tabIndex) {
if (onChanged != null)
onChanged(tabIndex);
}
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(views != null && views.isNotEmpty); assert(views != null && views.isNotEmpty);
assert(selectedIndex >= 0 && selectedIndex < views.length); assert(selectedIndex >= 0 && selectedIndex < views.length);
return new Column([ return new Column([
new TabBar( new TabBar(
labels: views.map((view) => view.label), labels: views.map((view) => view.label),
onChanged: _handleSelectedIndexChanged, onChanged: onChanged,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
isScrollable: isScrollable isScrollable: isScrollable
), ),
......
...@@ -4,35 +4,36 @@ ...@@ -4,35 +4,36 @@
import 'package:sky/material.dart'; import 'package:sky/material.dart';
import 'package:sky/painting.dart'; import 'package:sky/painting.dart';
import 'package:sky/src/widgets/animated_container.dart';
import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/basic.dart';
import 'package:sky/src/widgets/framework.dart'; import 'package:sky/src/widgets/framework.dart';
import 'package:sky/src/widgets/icon.dart'; import 'package:sky/src/widgets/icon.dart';
import 'package:sky/src/widgets/theme.dart'; import 'package:sky/src/widgets/theme.dart';
import 'package:sky/src/rendering/flex.dart';
class ToolBar extends StatelessComponent { class ToolBar extends StatelessComponent {
ToolBar({ ToolBar({
Key key, Key key,
this.left, this.left,
this.center, this.center,
this.right, this.right,
this.level: 2,
this.backgroundColor this.backgroundColor
}) : super(key: key); }) : super(key: key);
final Widget left; final Widget left;
final Widget center; final Widget center;
final List<Widget> right; final List<Widget> right;
final int level;
final Color backgroundColor; final Color backgroundColor;
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color toolbarColor = backgroundColor; Color color = backgroundColor;
IconThemeData iconThemeData; IconThemeData iconThemeData;
TextStyle centerStyle = Typography.white.title; TextStyle centerStyle = Typography.white.title;
TextStyle sideStyle = Typography.white.body1; TextStyle sideStyle = Typography.white.body1;
if (toolbarColor == null) { if (color == null) {
ThemeData themeData = Theme.of(context); ThemeData themeData = Theme.of(context);
toolbarColor = themeData.primaryColor; color = themeData.primaryColor;
if (themeData.primaryColorBrightness == ThemeBrightness.light) { if (themeData.primaryColorBrightness == ThemeBrightness.light) {
centerStyle = Typography.black.title; centerStyle = Typography.black.title;
sideStyle = Typography.black.body2; sideStyle = Typography.black.body2;
...@@ -44,11 +45,9 @@ class ToolBar extends StatelessComponent { ...@@ -44,11 +45,9 @@ class ToolBar extends StatelessComponent {
List<Widget> children = new List<Widget>(); List<Widget> children = new List<Widget>();
// left children
if (left != null) if (left != null)
children.add(left); children.add(left);
// center children (left-aligned, but takes all remaining space)
children.add( children.add(
new Flexible( new Flexible(
child: new Padding( child: new Padding(
...@@ -58,11 +57,16 @@ class ToolBar extends StatelessComponent { ...@@ -58,11 +57,16 @@ class ToolBar extends StatelessComponent {
) )
); );
// right children
if (right != null) if (right != null)
children.addAll(right); children.addAll(right);
Widget content = new Container( Widget content = new AnimatedContainer(
duration: kThemeChangeDuration,
padding: new EdgeDims.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(
backgroundColor: color,
boxShadow: level == 0 ? null : shadows[2]
),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: sideStyle, style: sideStyle,
child: new Column([ child: new Column([
...@@ -73,11 +77,6 @@ class ToolBar extends StatelessComponent { ...@@ -73,11 +77,6 @@ class ToolBar extends StatelessComponent {
], ],
justifyContent: FlexJustifyContent.end justifyContent: FlexJustifyContent.end
) )
),
padding: new EdgeDims.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(
backgroundColor: toolbarColor,
boxShadow: shadows[2]
) )
); );
......
...@@ -21,10 +21,10 @@ abstract class TransitionComponent extends StatefulComponent { ...@@ -21,10 +21,10 @@ abstract class TransitionComponent extends StatefulComponent {
Widget build(BuildContext context); Widget build(BuildContext context);
TransitionState createState() => new TransitionState(); _TransitionState createState() => new _TransitionState();
} }
class TransitionState extends State<TransitionComponent> { class _TransitionState extends State<TransitionComponent> {
void initState() { void initState() {
super.initState(); super.initState();
config.performance.addListener(_performanceChanged); config.performance.addListener(_performanceChanged);
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
/// The Flutter widget framework. /// The Flutter widget framework.
library widgets; library widgets;
export 'src/widgets/animated_component.dart';
export 'src/widgets/animated_container.dart'; export 'src/widgets/animated_container.dart';
export 'src/widgets/app.dart'; export 'src/widgets/app.dart';
export 'src/widgets/basic.dart'; export 'src/widgets/basic.dart';
...@@ -37,6 +36,7 @@ export 'src/widgets/material_button.dart'; ...@@ -37,6 +36,7 @@ export 'src/widgets/material_button.dart';
export 'src/widgets/mimic.dart'; export 'src/widgets/mimic.dart';
export 'src/widgets/mixed_viewport.dart'; export 'src/widgets/mixed_viewport.dart';
export 'src/widgets/navigator.dart'; export 'src/widgets/navigator.dart';
export 'src/widgets/placeholder.dart';
export 'src/widgets/popup_menu.dart'; export 'src/widgets/popup_menu.dart';
export 'src/widgets/popup_menu_item.dart'; export 'src/widgets/popup_menu_item.dart';
export 'src/widgets/progress_indicator.dart'; export 'src/widgets/progress_indicator.dart';
......
name: sky name: sky
version: 0.0.52 version: 0.0.53
author: Flutter Authors <flutter-dev@googlegroups.com> author: Flutter Authors <flutter-dev@googlegroups.com>
description: A framework for writing Flutter applications description: A framework for writing Flutter applications
homepage: http://flutter.io homepage: http://flutter.io
...@@ -9,8 +9,8 @@ dependencies: ...@@ -9,8 +9,8 @@ dependencies:
mojo_services: '>=0.1.0 <0.2.0' mojo_services: '>=0.1.0 <0.2.0'
mojo: '>=0.1.0 <0.2.0' mojo: '>=0.1.0 <0.2.0'
newton: ^0.1.4 newton: ^0.1.4
sky_engine: ^0.0.30 sky_engine: ^0.0.31
sky_services: ^0.0.30 sky_services: ^0.0.31
sky_tools: ^0.0.15 sky_tools: ^0.0.15
vector_math: ^1.4.3 vector_math: ^1.4.3
intl: ^0.12.4+2 intl: ^0.12.4+2
......
...@@ -9,49 +9,219 @@ class PhysicsBody { ...@@ -9,49 +9,219 @@ class PhysicsBody {
PhysicsBody(this.shape, { PhysicsBody(this.shape, {
this.tag: null, this.tag: null,
this.type: PhysicsBodyType.dynamic, this.type: PhysicsBodyType.dynamic,
this.density: 1.0, double density: 1.0,
this.friction: 0.0, double friction: 0.0,
this.restitution: 0.0, double restitution: 0.0,
this.isSensor: false, bool isSensor: false,
this.linearVelocity: Offset.zero, Offset linearVelocity: Offset.zero,
this.angularVelocity: 0.0, double angularVelocity: 0.0,
this.linearDampening: 0.0, this.linearDampening: 0.0,
this.angularDampening: 0.0, double awakeangularDampening: 0.0,
this.allowSleep: true, bool allowSleep: true,
this.awake: true, bool awake: true,
this.fixedRotation: false, bool fixedRotation: false,
this.bullet: false, bool bullet: false,
this.active: true, bool active: true,
this.gravityScale: 1.0 this.gravityScale: 1.0
}); }) {
this.density = density;
this.friction = friction;
this.restitution = restitution;
this.isSensor = isSensor;
this.linearVelocity = linearVelocity;
this.angularVelocity = angularVelocity;
this.angularDampening = angularDampening;
this.allowSleep = allowSleep;
this.awake = awake;
this.fixedRotation = fixedRotation;
this.bullet = bullet;
this.active = active;
}
Object tag; Object tag;
PhysicsShape shape; final PhysicsShape shape;
PhysicsBodyType type; PhysicsBodyType type;
double density; double _density;
double friction;
double restitution; double get density => _density;
bool isSensor;
set density(double density) {
_density = density;
if (_body == null)
return;
for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) {
f.setDensity(density);
}
}
double _friction;
double get friction => _friction;
set friction(double friction) {
_friction = friction;
if (_body == null)
return;
for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) {
f.setFriction(friction);
}
}
double _restitution;
double get restitution => _restitution;
set restitution(double restitution) {
_restitution = restitution;
if (_body == null)
return;
for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) {
f.setRestitution(restitution);
}
}
bool _isSensor;
bool get isSensor => _isSensor;
set isSensor(bool isSensor) {
_isSensor = isSensor;
if (_body == null)
return;
for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) {
f.setSensor(isSensor);
}
}
Offset _linearVelocity;
Offset get linearVelocity {
if (_body == null)
return _linearVelocity;
else {
double dx = _body.linearVelocity.x * _physicsNode.b2WorldToNodeConversionFactor;
double dy = _body.linearVelocity.y * _physicsNode.b2WorldToNodeConversionFactor;
return new Offset(dx, dy);
}
}
set linearVelocity(Offset linearVelocity) {
_linearVelocity = linearVelocity;
if (_body != null) {
Vector2 vec = new Vector2(
linearVelocity.dx / _physicsNode.b2WorldToNodeConversionFactor,
linearVelocity.dy / _physicsNode.b2WorldToNodeConversionFactor
);
_body.linearVelocity = vec;
}
}
double _angularVelocity;
Offset linearVelocity; double get angularVelocity {
double angularVelocity; if (_body == null)
return _angularVelocity;
else
return _body.angularVelocity;
}
set angularVelocity(double angularVelocity) {
_angularVelocity = angularVelocity;
if (_body != null) {
_body.angularVelocity = angularVelocity;
}
}
// TODO: Should this be editable in box2d.Body ?
final double linearDampening;
double _angularDampening;
double get angularDampening => _angularDampening;
double linearDampening; set angularDampening(double angularDampening) {
_angularDampening = angularDampening;
double angularDampening; if (_body != null)
_body.angularDamping = angularDampening;
}
bool _allowSleep;
bool allowSleep; bool get allowSleep => _allowSleep;
bool awake; set allowSleep(bool allowSleep) {
_allowSleep = allowSleep;
bool fixedRotation; if (_body != null)
_body.setSleepingAllowed(allowSleep);
}
bool bullet; bool _awake;
bool get awake {
if (_body != null)
return _body.isAwake();
else
return _awake;
}
set awake(bool awake) {
_awake = awake;
if (_body != null)
_body.setAwake(awake);
}
bool active; bool _fixedRotation;
bool get fixedRotation => _fixedRotation;
set fixedRotation(bool fixedRotation) {
_fixedRotation = fixedRotation;
if (_body != null)
_body.setFixedRotation(fixedRotation);
}
bool _bullet;
bool get bullet => _bullet;
set bullet(bool bullet) {
_bullet = bullet;
if (_body != null) {
_body.setBullet(bullet);
}
}
bool _active;
bool get active {
if (_body != null)
return _body.isActive();
else
return _active;
}
set active(bool active) {
_active = active;
if (_body != null)
_body.setActive(active);
}
double gravityScale; double gravityScale;
......
...@@ -66,6 +66,10 @@ class BadDisposeWidgetState extends State<BadDisposeWidget> { ...@@ -66,6 +66,10 @@ class BadDisposeWidgetState extends State<BadDisposeWidget> {
void main() { void main() {
dynamic cachedException; dynamic cachedException;
// ** WARNING **
// THIS TEST OVERRIDES THE NORMAL EXCEPTION HANDLING
// AND DOES NOT REPORT EXCEPTIONS FROM THE FRAMEWORK
setUp(() { setUp(() {
assert(cachedException == null); assert(cachedException == null);
debugWidgetsExceptionHandler = (String context, dynamic exception, StackTrace stack) { debugWidgetsExceptionHandler = (String context, dynamic exception, StackTrace stack) {
......
import 'package:sky/widgets.dart';
import 'package:test/test.dart';
import 'widget_tester.dart';
class TestFocusable extends StatelessComponent {
TestFocusable(this.no, this.yes, GlobalKey key) : super(key: key);
final String no;
final String yes;
Widget build(BuildContext context) {
bool focused = Focus.at(context, this);
return new GestureDetector(
onTap: () { Focus.moveTo(context, this); },
child: new Text(focused ? yes : no)
);
}
}
void main() {
test('Can have multiple focused children and they update accordingly', () {
testWidgets((WidgetTester tester) {
GlobalKey keyA = new GlobalKey();
GlobalKey keyB = new GlobalKey();
tester.pumpWidget(
new Focus(
child: new Column([
// reverse these when you fix https://github.com/flutter/engine/issues/1495
new TestFocusable('b', 'B FOCUSED', keyB),
new TestFocusable('a', 'A FOCUSED', keyA),
])
)
);
expect(tester.findText('a'), isNull);
expect(tester.findText('A FOCUSED'), isNotNull);
expect(tester.findText('b'), isNotNull);
expect(tester.findText('B FOCUSED'), isNull);
tester.tap(tester.findText('A FOCUSED'));
tester.pump();
expect(tester.findText('a'), isNull);
expect(tester.findText('A FOCUSED'), isNotNull);
expect(tester.findText('b'), isNotNull);
expect(tester.findText('B FOCUSED'), isNull);
tester.tap(tester.findText('A FOCUSED'));
tester.pump();
expect(tester.findText('a'), isNull);
expect(tester.findText('A FOCUSED'), isNotNull);
expect(tester.findText('b'), isNotNull);
expect(tester.findText('B FOCUSED'), isNull);
tester.tap(tester.findText('b'));
tester.pump();
expect(tester.findText('a'), isNotNull);
expect(tester.findText('A FOCUSED'), isNull);
expect(tester.findText('b'), isNull);
expect(tester.findText('B FOCUSED'), isNotNull);
tester.tap(tester.findText('a'));
tester.pump();
expect(tester.findText('a'), isNull);
expect(tester.findText('A FOCUSED'), isNotNull);
expect(tester.findText('b'), isNotNull);
expect(tester.findText('B FOCUSED'), isNull);
});
});
}
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