blob: eec0814b66e7640ad75c831236aa3ab7462744c7 [file] [log] [blame]
// 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);
const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200);
class StockHome extends StatefulComponent {
StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater);
Navigator navigator;
List<Stock> stocks;
StockMode stockMode;
ModeUpdater modeUpdater;
void syncConstructorArguments(StockHome source) {
navigator = source.navigator;
stocks = source.stocks;
stockMode = source.stockMode;
modeUpdater = source.modeUpdater;
}
bool _isSearching = false;
String _searchQuery;
AnimationStatus _snackBarStatus = AnimationStatus.dismissed;
bool _isSnackBarShowing = false;
void _handleSearchBegin() {
navigator.pushState(this, (_) {
setState(() {
_isSearching = false;
_searchQuery = null;
});
});
setState(() {
_isSearching = true;
});
}
void _handleSearchEnd() {
assert(navigator.currentRoute is RouteState);
assert((navigator.currentRoute as RouteState).owner == this); // TODO(ianh): remove cast once analyzer is cleverer
navigator.pop();
setState(() {
_isSearching = false;
_searchQuery = null;
});
}
void _handleSearchQueryChanged(String query) {
setState(() {
_searchQuery = query;
});
}
bool _drawerShowing = false;
AnimationStatus _drawerStatus = AnimationStatus.dismissed;
void _handleOpenDrawer() {
setState(() {
_drawerShowing = true;
_drawerStatus = AnimationStatus.forward;
});
}
void _handleDrawerDismissed() {
setState(() {
_drawerStatus = AnimationStatus.dismissed;
});
}
bool _menuShowing = false;
AnimationStatus _menuStatus = AnimationStatus.dismissed;
void _handleMenuShow() {
setState(() {
_menuShowing = true;
_menuStatus = AnimationStatus.forward;
});
}
void _handleMenuHide() {
setState(() {
_menuShowing = false;
});
}
void _handleMenuDismissed() {
setState(() {
_menuStatus = AnimationStatus.dismissed;
});
}
bool _autorefresh = false;
void _handleAutorefreshChanged(bool value) {
setState(() {
_autorefresh = value;
});
}
EventDisposition _handleStockModeChange(StockMode value) {
setState(() {
stockMode = value;
});
if (modeUpdater != null)
modeUpdater(value);
return EventDisposition.processed;
}
Drawer buildDrawer() {
if (_drawerStatus == AnimationStatus.dismissed)
return null;
assert(_drawerShowing); // TODO(mpcomplete): this is always true
return new Drawer(
level: 3,
showing: _drawerShowing,
onDismissed: _handleDrawerDismissed,
navigator: navigator,
children: [
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 DrawerDivider(),
new DrawerItem(
icon: 'action/thumb_up',
onPressed: () => _handleStockModeChange(StockMode.optimistic),
child: new Flex([
new Flexible(child: new Text('Optimistic')),
new Radio(value: StockMode.optimistic, groupValue: stockMode, onChanged: _handleStockModeChange)
])
),
new DrawerItem(
icon: 'action/thumb_down',
onPressed: () => _handleStockModeChange(StockMode.pessimistic),
child: new Flex([
new Flexible(child: new Text('Pessimistic')),
new Radio(value: StockMode.pessimistic, groupValue: 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'))
]
);
}
EventDisposition _handleShowSettings() {
navigator.pop();
navigator.pushNamed('/settings');
return EventDisposition.processed;
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/menu",
onPressed: _handleOpenDrawer),
center: new Text('Stocks'),
right: [
new IconButton(
icon: "action/search",
onPressed: _handleSearchBegin),
new IconButton(
icon: "navigation/more_vert",
onPressed: _handleMenuShow)
]
);
}
int selectedTabIndex = 0;
List<String> portfolioSymbols = ["AAPL","FIZZ", "FIVE", "FLAT", "ZINC", "ZNGA"];
Iterable<Stock> _filterByPortfolio(Iterable<Stock> stocks) {
return stocks.where((stock) => portfolioSymbols.contains(stock.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 buildMarketStockList() {
return new Stocklist(stocks: _filterBySearchQuery(stocks).toList());
}
Widget buildPortfolioStocklist() {
return new Stocklist(stocks: _filterBySearchQuery(_filterByPortfolio(stocks)).toList());
}
Widget buildTabNavigator() {
List<TabNavigatorView> views = <TabNavigatorView>[
new TabNavigatorView(
label: const TabLabel(text: 'MARKET'),
builder: buildMarketStockList
),
new TabNavigatorView(
label: const TabLabel(text: 'PORTFOLIO'),
builder: buildPortfolioStocklist
)
];
return new TabNavigator(
views: views,
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(this).accentColor,
onPressed: _handleSearchEnd
),
center: new Input(
key: searchFieldKey,
placeholder: 'Search stocks',
onChanged: _handleSearchQueryChanged
),
backgroundColor: Theme.of(this).canvasColor
);
}
void _handleUndo() {
setState(() {
_isSnackBarShowing = false;
});
}
Anchor _snackBarAnchor = new Anchor();
Widget buildSnackBar() {
if (_snackBarStatus == AnimationStatus.dismissed)
return null;
return new SnackBar(
showing: _isSnackBarShowing,
anchor: _snackBarAnchor,
content: new Text("Stock purchased!"),
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)],
onDismissed: () { setState(() { _snackBarStatus = AnimationStatus.dismissed; }); }
);
}
void _handleStockPurchased() {
setState(() {
_isSnackBarShowing = true;
_snackBarStatus = AnimationStatus.forward;
});
}
Widget buildFloatingActionButton() {
return _snackBarAnchor.build(
new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24),
backgroundColor: colors.RedAccent[200],
onPressed: _handleStockPurchased
));
}
void addMenuToOverlays(List<Widget> overlays) {
if (_menuStatus == AnimationStatus.dismissed)
return;
overlays.add(new ModalOverlay(
children: [new StockMenu(
showing: _menuShowing,
onDismissed: _handleMenuDismissed,
navigator: navigator,
autorefresh: _autorefresh,
onAutorefreshChanged: _handleAutorefreshChanged
)],
onDismiss: _handleMenuHide));
}
Widget build() {
List<Widget> overlays = [
new Scaffold(
toolbar: _isSearching ? buildSearchBar() : buildToolBar(),
body: buildTabNavigator(),
snackBar: buildSnackBar(),
floatingActionButton: buildFloatingActionButton(),
drawer: buildDrawer()
),
];
addMenuToOverlays(overlays);
return new Stack(overlays);
}
}