From d44f8f2dbcdb00ae5f6ffde271ea0cf483252f5e Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Thu, 18 Jun 2015 15:36:04 -0700 Subject: [PATCH] Make back button control drawer in stocks app Currently you lose your scroll and drawer state when coming back from the settings pane. I think we should solve this by having the Navigator maintain a Stack and keeping the StockHome alive underneath it. But this is good enough for a first iteration. R=abarth@chromium.org, abarth Review URL: https://codereview.chromium.org/1191153002. --- examples/stocks2/lib/stock_app.dart | 40 +++++++++++++------ examples/stocks2/lib/stock_home.dart | 32 ++++++++++----- examples/widgets/navigation.dart | 9 ++--- sdk/lib/widgets/drawer.dart | 10 ++--- sdk/lib/widgets/navigator.dart | 60 +++++++++++++++------------- 5 files changed, 91 insertions(+), 60 deletions(-) diff --git a/examples/stocks2/lib/stock_app.dart b/examples/stocks2/lib/stock_app.dart index 6ed6dd4a1ce..2398238cd43 100644 --- a/examples/stocks2/lib/stock_app.dart +++ b/examples/stocks2/lib/stock_app.dart @@ -7,29 +7,45 @@ import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/navigator.dart'; import 'package:sky/widgets/widget.dart'; +import 'stock_data.dart'; import 'stock_home.dart'; import 'stock_settings.dart'; class StocksApp extends App { - NavigationState _navState = new NavigationState([ - new Route(name: '/', builder: (navigator) => new StockHome(navigator)), - new Route(name: '/settings', builder: (navigator) => new StockSettings(navigator)), - ]); + StocksApp() { + _navigationState = new NavigationState([ + new Route( + name: '/', + builder: (navigator, route) => new StockHome(navigator, route, _stocks) + ), + new Route( + name: '/settings', + builder: (navigator, route) => new StockSettings(navigator) + ), + ]); + } + + void didMount() { + new StockDataFetcher((StockData data) { + setState(() { + data.appendTo(_stocks); + }); + }); + } + + final List _stocks = []; + NavigationState _navigationState; void onBack() { - if (_navState.hasPrevious()) { - setState(() { - _navState.pop(); - }); - return; - } - print ("Should exit app here"); + setState(() { + _navigationState.pop(); + }); // TODO(jackson): Need a way to invoke default back behavior here } Widget build() { - return new Navigator(_navState); + return new Navigator(_navigationState); } } diff --git a/examples/stocks2/lib/stock_home.dart b/examples/stocks2/lib/stock_home.dart index cc98bb8f7e6..a0e8ce37150 100644 --- a/examples/stocks2/lib/stock_home.dart +++ b/examples/stocks2/lib/stock_home.dart @@ -29,19 +29,19 @@ enum StockMode { optimistic, pessimistic } class StockHome extends Component { - StockHome(this._navigator) { + StockHome(this.navigator, RouteBase route, this.stocks) : super(stateful: true) { // if (debug) // new Timer(new Duration(seconds: 1), dumpState); - new StockDataFetcher((StockData data) { - setState(() { - data.appendTo(_stocks); - }); - }); _drawerController = new DrawerController(_handleDrawerStatusChanged); } - List _stocks = []; - Navigator _navigator; + void syncFields(StockHome source) { + navigator = source.navigator; + stocks = source.stocks; + } + + Navigator navigator; + List stocks; bool _isSearching = false; String _searchQuery; @@ -69,6 +69,9 @@ class StockHome extends Component { bool _drawerShowing = false; void _handleDrawerStatusChanged(bool showing) { + if (!showing && navigator.currentRoute.name == "/drawer") { + navigator.pop(); + } setState(() { _drawerShowing = showing; }); @@ -137,7 +140,7 @@ class StockHome extends Component { new MenuDivider(), new MenuItem( icon: 'action/settings', - onPressed: () => _navigator.pushNamed('/settings'), + onPressed: () => navigator.pushNamed('/settings'), children: [new Text('Settings')]), new MenuItem( icon: 'action/help', @@ -146,11 +149,18 @@ class StockHome extends Component { ); } + void _handleOpenDrawer() { + _drawerController.open(); + navigator.pushState("/drawer", (_) { + _drawerController.close(); + }); + } + Widget buildToolBar() { return new ToolBar( left: new IconButton( icon: 'navigation/menu_white', - onPressed: _drawerController.toggle), + onPressed: _handleOpenDrawer), center: new Text('Stocks', style: typography.white.title), right: [ new IconButton( @@ -194,7 +204,7 @@ class StockHome extends Component { List overlays = [ new Scaffold( toolbar: _isSearching ? buildSearchBar() : buildToolBar(), - body: new Stocklist(stocks: _stocks, query: _searchQuery), + body: new Stocklist(stocks: stocks, query: _searchQuery), floatingActionButton: new FloatingActionButton( child: new Icon(type: 'content/add_white', size: 24) ), diff --git a/examples/widgets/navigation.dart b/examples/widgets/navigation.dart index 6f1d3d99bdf..82a9b35bbc7 100644 --- a/examples/widgets/navigation.dart +++ b/examples/widgets/navigation.dart @@ -4,13 +4,12 @@ import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/navigator.dart'; -import 'package:sky/widgets/transition.dart'; import 'package:sky/widgets/raised_button.dart'; List routes = [ new Route( name: 'home', - builder: (navigator) => new Container( + builder: (navigator, route) => new Container( padding: const EdgeDims.all(20.0), decoration: new BoxDecoration(backgroundColor: const Color(0xFFCCCCCC)), child: new Block([ @@ -28,14 +27,14 @@ List routes = [ ), new Route( name: 'shopping', - builder: (navigator) => new Container( + builder: (navigator, route) => new Container( padding: const EdgeDims.all(20.0), decoration: new BoxDecoration(backgroundColor: const Color(0xFFBF5FFF)), child: new Block([ new Text("Village Shop"), new RaisedButton( child: new Text('RETURN HOME'), - onPressed: () => navigator.back() + onPressed: () => navigator.pop() ), new RaisedButton( child: new Text('GO TO DUNGEON'), @@ -46,7 +45,7 @@ List routes = [ ), new Route( name: 'adventure', - builder: (navigator) => new Container( + builder: (navigator, route) => new Container( padding: const EdgeDims.all(20.0), decoration: new BoxDecoration(backgroundColor: const Color(0xFFDC143C)), child: new Block([ diff --git a/sdk/lib/widgets/drawer.dart b/sdk/lib/widgets/drawer.dart index 67eccd310dc..ac84a95b04a 100644 --- a/sdk/lib/widgets/drawer.dart +++ b/sdk/lib/widgets/drawer.dart @@ -54,9 +54,9 @@ class DrawerController { bool get isClosed => position.value == -_kWidth; bool get _isMostlyClosed => position.value <= -_kWidth / 2; - void toggle() => _isMostlyClosed ? _open() : _close(); + void toggle() => _isMostlyClosed ? open() : close(); - void handleMaskTap(_) => _close(); + void handleMaskTap(_) => close(); void handlePointerDown(_) => position.stop(); void handlePointerMove(sky.PointerEvent event) { @@ -75,11 +75,11 @@ class DrawerController { _settle(); } - void _open() => _animateToPosition(0.0); + void open() => _animateToPosition(0.0); - void _close() => _animateToPosition(-_kWidth); + void close() => _animateToPosition(-_kWidth); - void _settle() => _isMostlyClosed ? _close() : _open(); + void _settle() => _isMostlyClosed ? close() : open(); void _animateToPosition(double targetPosition) { double distance = (targetPosition - position.value).abs(); diff --git a/sdk/lib/widgets/navigator.dart b/sdk/lib/widgets/navigator.dart index 3a6cad17987..8ec48230396 100644 --- a/sdk/lib/widgets/navigator.dart +++ b/sdk/lib/widgets/navigator.dart @@ -4,18 +4,34 @@ import 'basic.dart'; -typedef Widget Builder(Navigator navigator); +typedef Widget Builder(Navigator navigator, RouteBase route); abstract class RouteBase { RouteBase({ this.name }); final String name; - Widget build(Navigator navigator); + Widget build(Navigator navigator, RouteBase route); + void popState() { } } class Route extends RouteBase { Route({ String name, this.builder }) : super(name: name); final Builder builder; - Widget build(Navigator navigator) => builder(navigator); + Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); +} + +class RouteState extends RouteBase { + + RouteState({this.callback, this.route, String name}) : super(name: name); + + RouteBase route; + Function callback; + + Widget build(Navigator navigator, _) => route.build(navigator, this); + + void popState() { + if (callback != null) + callback(this); + } } class NavigationState { @@ -51,25 +67,16 @@ class NavigationState { void pop() { if (historyIndex > 0) { + history[historyIndex].popState(); history.removeLast(); historyIndex--; } } - - void back() { - if (historyIndex > 0) - historyIndex--; - } - - void forward() { - historyIndex++; - assert(historyIndex < history.length); - } } class Navigator extends Component { - Navigator(this.state, { String key }) : super(key: key); + Navigator(this.state, { String key }) : super(key: key, stateful: true); NavigationState state; @@ -77,6 +84,17 @@ class Navigator extends Component { state = source.state; } + RouteBase get currentRoute => state.currentRoute; + + void pushState(String name, Function callback) { + RouteBase route = new RouteState( + name: name, + callback: callback, + route: state.currentRoute + ); + push(route); + } + void pushNamed(String name) { setState(() { state.pushNamed(name); @@ -95,19 +113,7 @@ class Navigator extends Component { }); } - void back() { - setState(() { - state.back(); - }); - } - - void forward() { - setState(() { - state.forward(); - }); - } - Widget build() { - return state.currentRoute.build(this); + return state.currentRoute.build(this, state.currentRoute); } }