flutter/examples/stocks/lib/stock_home.dart
Adam Barth 2eec30111a Use Navigator to drive SnackBar
Now SnackBar is an ephemeral route that uses a Placeholder to put itself into
the Scaffold.

Fixes #673
2015-10-05 17:12:50 -07:00

247 lines
7.1 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(config.navigator.currentRoute is StateRoute);
assert((config.navigator.currentRoute as StateRoute).owner == this); // TODO(ianh): remove cast once analyzer is cleverer
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([
new DrawerHeader(child: new Text('Stocks')),
new DrawerItem(
icon: 'action/assessment',
selected: true,
child: new Text('Stock List')
),
new DrawerItem(
icon: 'action/account_balance',
child: new Text('Account Balance')
),
new DrawerItem(
icon: 'device/dvr',
onPressed: () { debugDumpApp(); },
child: new Text('Dump App to Console')
),
new DrawerDivider(),
new DrawerItem(
icon: 'action/thumb_up',
onPressed: () => _handleStockModeChange(StockMode.optimistic),
child: new Row([
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([
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(
left: new IconButton(
icon: "navigation/menu",
onPressed: _showDrawer
),
center: new Text('Stocks'),
right: [
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((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.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: (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",
color: Theme.of(context).accentColor,
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: [
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()
);
}
}