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