OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 import 'package:sky/framework/components/tool_bar.dart'; | |
6 import 'package:sky/framework/components/drawer.dart'; | |
7 import 'package:sky/framework/components/drawer_header.dart'; | |
8 import 'package:sky/framework/components/floating_action_button.dart'; | |
9 import 'package:sky/framework/components/icon.dart'; | |
10 import 'package:sky/framework/components/icon_button.dart'; | |
11 import 'package:sky/framework/components/input.dart'; | |
12 import 'package:sky/framework/components/menu_divider.dart'; | |
13 import 'package:sky/framework/components/menu_item.dart'; | |
14 import 'package:sky/framework/components/modal_overlay.dart'; | |
15 import 'package:sky/framework/components/popup_menu.dart'; | |
16 import 'package:sky/framework/components/radio.dart'; | |
17 import 'package:sky/framework/components/scaffold.dart'; | |
18 import 'package:sky/framework/fn.dart'; | |
19 import 'package:sky/framework/theme/typography.dart' as typography; | |
20 import 'package:sky/framework/theme/colors.dart'; | |
21 import 'stock_data.dart'; | |
22 import 'stock_list.dart'; | |
23 import 'stock_menu.dart'; | |
24 | |
25 import 'dart:async'; | |
26 import 'package:sky/framework/layout.dart'; | |
27 | |
28 const bool debug = false; // set to true to dump the DOM for debugging purposes | |
29 | |
30 enum StockMode { Optimistic, Pessimistic } | |
31 | |
32 class StocksApp extends App { | |
33 | |
34 static final Style _toolBarStyle = new Style(''' | |
35 background-color: ${Purple[500]};'''); | |
36 | |
37 static final Style _searchBarStyle = new Style(''' | |
38 background-color: ${Grey[50]};'''); | |
39 | |
40 static final Style _titleStyle = new Style(''' | |
41 ${typography.white.title};'''); | |
42 | |
43 List<Stock> _stocks = []; | |
44 | |
45 StocksApp() : super() { | |
46 if (debug) | |
47 new Timer(new Duration(seconds: 1), dumpState); | |
48 new StockDataFetcher((StockData data) { | |
49 setState(() { | |
50 data.appendTo(_stocks); | |
51 }); | |
52 }); | |
53 _drawerController = new DrawerController(_handleDrawerStatusChanged); | |
54 } | |
55 | |
56 bool _isSearching = false; | |
57 String _searchQuery; | |
58 | |
59 void _handleSearchBegin(_) { | |
60 setState(() { | |
61 _isSearching = true; | |
62 }); | |
63 } | |
64 | |
65 void _handleSearchEnd(_) { | |
66 setState(() { | |
67 _isSearching = false; | |
68 _searchQuery = null; | |
69 }); | |
70 } | |
71 | |
72 void _handleSearchQueryChanged(String query) { | |
73 setState(() { | |
74 _searchQuery = query; | |
75 }); | |
76 } | |
77 | |
78 DrawerController _drawerController; | |
79 bool _drawerShowing = false; | |
80 | |
81 void _handleDrawerStatusChanged(bool showing) { | |
82 setState(() { | |
83 _drawerShowing = showing; | |
84 }); | |
85 } | |
86 | |
87 PopupMenuController _menuController; | |
88 | |
89 void _handleMenuShow(_) { | |
90 setState(() { | |
91 _menuController = new PopupMenuController(); | |
92 _menuController.open(); | |
93 }); | |
94 } | |
95 | |
96 void _handleMenuHide(_) { | |
97 setState(() { | |
98 _menuController.close().then((_) { | |
99 setState(() { | |
100 _menuController = null; | |
101 }); | |
102 }); | |
103 }); | |
104 } | |
105 | |
106 bool _autorefresh = false; | |
107 void _handleAutorefreshChanged(bool value) { | |
108 setState(() { | |
109 _autorefresh = value; | |
110 }); | |
111 } | |
112 | |
113 StockMode _stockMode = StockMode.Optimistic; | |
114 void _handleStockModeChange(StockMode value) { | |
115 setState(() { | |
116 _stockMode = value; | |
117 }); | |
118 } | |
119 | |
120 static FlexBoxParentData _flex1 = new FlexBoxParentData()..flex = 1; | |
121 | |
122 Drawer buildDrawer() { | |
123 return new Drawer( | |
124 controller: _drawerController, | |
125 level: 3, | |
126 children: [ | |
127 new DrawerHeader(children: [new Text('Stocks')]), | |
128 new MenuItem( | |
129 key: 'Stock list', | |
130 icon: 'action/assessment', | |
131 children: [new Text('Stock List')]), | |
132 new MenuItem( | |
133 key: 'Account Balance', | |
134 icon: 'action/account_balance', | |
135 children: [new Text('Account Balance')]), | |
136 new MenuDivider(key: 'div1'), | |
137 new MenuItem( | |
138 key: 'Optimistic Menu Item', | |
139 icon: 'action/thumb_up', | |
140 onGestureTap: (event) => _handleStockModeChange(StockMode.Optimistic), | |
141 children: [ | |
142 new ParentDataNode(new Text('Optimistic'), _flex1), | |
143 new Radio(key: 'optimistic-radio', value: StockMode.Optimistic, grou
pValue: _stockMode, onChanged: _handleStockModeChange) | |
144 ]), | |
145 new MenuItem( | |
146 key: 'Pessimistic Menu Item', | |
147 icon: 'action/thumb_down', | |
148 onGestureTap: (event) => _handleStockModeChange(StockMode.Pessimistic)
, | |
149 children: [ | |
150 new ParentDataNode(new Text('Pessimistic'), _flex1), | |
151 new Radio(key: 'pessimistic-radio', value: StockMode.Pessimistic, gr
oupValue: _stockMode, onChanged: _handleStockModeChange) | |
152 ]), | |
153 new MenuDivider(key: 'div2'), | |
154 new MenuItem( | |
155 key: 'Settings', | |
156 icon: 'action/settings', | |
157 children: [new Text('Settings')]), | |
158 new MenuItem( | |
159 key: 'Help & Feedback', | |
160 icon: 'action/help', | |
161 children: [new Text('Help & Feedback')]) | |
162 ] | |
163 ); | |
164 } | |
165 | |
166 UINode buildToolBar() { | |
167 return new StyleNode( | |
168 new ToolBar( | |
169 left: new IconButton( | |
170 icon: 'navigation/menu_white', | |
171 onGestureTap: _drawerController.toggle), | |
172 center: new Container( | |
173 style: _titleStyle, | |
174 children: [new Text('Stocks')]), | |
175 right: [ | |
176 new IconButton( | |
177 icon: 'action/search_white', | |
178 onGestureTap: _handleSearchBegin), | |
179 new IconButton( | |
180 icon: 'navigation/more_vert_white', | |
181 onGestureTap: _handleMenuShow) | |
182 ]), | |
183 _toolBarStyle); | |
184 } | |
185 | |
186 // TODO(abarth): Should we factor this into a SearchBar in the framework? | |
187 UINode buildSearchBar() { | |
188 return new StyleNode( | |
189 new ToolBar( | |
190 left: new IconButton( | |
191 icon: 'navigation/arrow_back_grey600', | |
192 onGestureTap: _handleSearchEnd), | |
193 center: new Input( | |
194 focused: true, | |
195 placeholder: 'Search stocks', | |
196 onChanged: _handleSearchQueryChanged)), | |
197 _searchBarStyle); | |
198 } | |
199 | |
200 void addMenuToOverlays(List<UINode> overlays) { | |
201 if (_menuController == null) | |
202 return; | |
203 overlays.add(new ModalOverlay( | |
204 children: [new StockMenu( | |
205 controller: _menuController, | |
206 autorefresh: _autorefresh, | |
207 onAutorefreshChanged: _handleAutorefreshChanged | |
208 )], | |
209 onDismiss: _handleMenuHide)); | |
210 } | |
211 | |
212 UINode build() { | |
213 List<UINode> overlays = []; | |
214 addMenuToOverlays(overlays); | |
215 | |
216 return new Scaffold( | |
217 header: _isSearching ? buildSearchBar() : buildToolBar(), | |
218 content: new Stocklist(stocks: _stocks, query: _searchQuery), | |
219 fab: new FloatingActionButton( | |
220 content: new Icon(type: 'content/add_white', size: 24), level: 3), | |
221 drawer: _drawerShowing ? buildDrawer() : null, | |
222 overlays: overlays | |
223 ); | |
224 } | |
225 } | |
OLD | NEW |