flutter/examples/stocks/lib/stock_home.dart
Hixie 1f40d96fbf Improve debugging output
Teach dumpRenderTree() to draw actual trees.
Make the TextStyle output terser so it doesn't overflow the output.
Make debugDumpApp() say what mode we're in (checked vs release).
Hide lifecycle state from release mode dumps (since it's checked-only state).
2015-10-15 11:23:23 -07:00

273 lines
7.9 KiB
Dart

// 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.
part of stocks;
typedef void ModeUpdater(StockMode mode);
class StockHome extends StatefulComponent {
StockHome(this.navigator, this.stocks, this.symbols, this.stockMode, this.modeUpdater);
final NavigatorState navigator;
final Map<String, Stock> stocks;
final List<String> symbols;
final StockMode stockMode;
final ModeUpdater modeUpdater;
StockHomeState createState() => new StockHomeState();
}
class StockHomeState extends State<StockHome> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
bool _isSearching = false;
String _searchQuery;
void _handleSearchBegin() {
config.navigator.pushState(this, (_) {
setState(() {
_isSearching = false;
_searchQuery = null;
});
});
setState(() {
_isSearching = true;
});
}
void _handleSearchEnd() {
assert(() {
final StateRoute currentRoute = config.navigator.currentRoute;
assert(currentRoute.owner == this);
});
config.navigator.pop();
setState(() {
_isSearching = false;
_searchQuery = null;
});
}
void _handleSearchQueryChanged(String query) {
setState(() {
_searchQuery = query;
});
}
bool _autorefresh = false;
void _handleAutorefreshChanged(bool value) {
setState(() {
_autorefresh = value;
});
}
void _handleStockModeChange(StockMode value) {
if (config.modeUpdater != null)
config.modeUpdater(value);
}
void _handleMenuShow() {
showStockMenu(config.navigator,
autorefresh: _autorefresh,
onAutorefreshChanged: _handleAutorefreshChanged
);
}
void _showDrawer() {
showDrawer(
navigator: config.navigator,
child: new Block(<Widget>[
new DrawerHeader(child: new Text('Stocks')),
new DrawerItem(
icon: 'action/assessment',
selected: true,
child: new Text('Stock List')
),
new DrawerItem(
icon: 'action/account_balance',
onPressed: () {
showDialog(config.navigator, (NavigatorState navigator) {
return new Dialog(
title: new Text('Not Implemented'),
content: new Text('This feature has not yet been implemented.'),
actions: <Widget>[
new FlatButton(
child: new Text('USE IT'),
enabled: false,
onPressed: () {
navigator.pop(false);
}
),
new FlatButton(
child: new Text('OH WELL'),
onPressed: () {
navigator.pop(false);
}
),
]
);
});
},
child: new Text('Account Balance')
),
new DrawerItem(
icon: 'device/dvr',
onPressed: () { debugDumpApp(); debugDumpRenderTree(); },
child: new Text('Dump App to Console')
),
new DrawerDivider(),
new DrawerItem(
icon: 'action/thumb_up',
onPressed: () => _handleStockModeChange(StockMode.optimistic),
child: new Row(<Widget>[
new Flexible(child: new Text('Optimistic')),
new Radio(value: StockMode.optimistic, groupValue: config.stockMode, onChanged: _handleStockModeChange)
])
),
new DrawerItem(
icon: 'action/thumb_down',
onPressed: () => _handleStockModeChange(StockMode.pessimistic),
child: new Row(<Widget>[
new Flexible(child: new Text('Pessimistic')),
new Radio(value: StockMode.pessimistic, groupValue: config.stockMode, onChanged: _handleStockModeChange)
])
),
new DrawerDivider(),
new DrawerItem(
icon: 'action/settings',
onPressed: _handleShowSettings,
child: new Text('Settings')),
new DrawerItem(
icon: 'action/help',
child: new Text('Help & Feedback'))
])
);
}
void _handleShowSettings() {
config.navigator.pop();
config.navigator.pushNamed('/settings');
}
Widget buildToolBar() {
return new ToolBar(
level: 0,
left: new IconButton(
icon: "navigation/menu",
onPressed: _showDrawer
),
center: new Text('Stocks'),
right: <Widget>[
new IconButton(
icon: "action/search",
onPressed: _handleSearchBegin
),
new IconButton(
icon: "navigation/more_vert",
onPressed: _handleMenuShow
)
]
);
}
int selectedTabIndex = 0;
Iterable<Stock> _getStockList(Iterable<String> symbols) {
return symbols.map((String symbol) => config.stocks[symbol]);
}
Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
if (_searchQuery == null)
return stocks;
RegExp regexp = new RegExp(_searchQuery, caseSensitive: false);
return stocks.where((Stock stock) => stock.symbol.contains(regexp));
}
Widget buildStockList(BuildContext context, Iterable<Stock> stocks) {
return new StockList(
stocks: stocks.toList(),
onAction: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) {
setState(() {
stock.percentChange = 100.0 * (1.0 / stock.lastSale);
stock.lastSale += 1.0;
});
},
onOpen: (Stock stock, GlobalKey row, GlobalKey arrowKey, GlobalKey symbolKey, GlobalKey priceKey) {
config.navigator.pushNamed('/stock/${stock.symbol}');
}
);
}
static const List<String> portfolioSymbols = const <String>["AAPL","FIZZ", "FIVE", "FLAT", "ZINC", "ZNGA"];
Widget buildTabNavigator() {
return new TabNavigator(
views: <TabNavigatorView>[
new TabNavigatorView(
label: const TabLabel(text: 'MARKET'),
builder: (BuildContext context) => buildStockList(context, _filterBySearchQuery(_getStockList(config.symbols)).toList())
),
new TabNavigatorView(
label: const TabLabel(text: 'PORTFOLIO'),
builder: (BuildContext context) => buildStockList(context, _filterBySearchQuery(_getStockList(portfolioSymbols)).toList())
)
],
selectedIndex: selectedTabIndex,
onChanged: (int tabIndex) {
setState(() { selectedTabIndex = tabIndex; } );
}
);
}
static GlobalKey searchFieldKey = new GlobalKey();
// TODO(abarth): Should we factor this into a SearchBar in the framework?
Widget buildSearchBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/arrow_back",
colorFilter: new ui.ColorFilter.mode(Theme.of(context).accentColor, ui.TransferMode.srcATop),
onPressed: _handleSearchEnd
),
center: new Input(
key: searchFieldKey,
placeholder: 'Search stocks',
onChanged: _handleSearchQueryChanged
),
backgroundColor: Theme.of(context).canvasColor
);
}
void _handleUndo() {
config.navigator.pop();
}
void _handleStockPurchased() {
showSnackBar(
navigator: config.navigator,
placeholderKey: _snackBarPlaceholderKey,
content: new Text("Stock purchased!"),
actions: <SnackBarAction>[
new SnackBarAction(label: "UNDO", onPressed: _handleUndo)
]
);
}
Widget buildFloatingActionButton() {
return new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24),
backgroundColor: Colors.redAccent[200],
onPressed: _handleStockPurchased
);
}
Widget build(BuildContext context) {
return new Scaffold(
toolBar: _isSearching ? buildSearchBar() : buildToolBar(),
body: buildTabNavigator(),
snackBar: new Placeholder(key: _snackBarPlaceholderKey),
floatingActionButton: buildFloatingActionButton()
);
}
}