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.
This commit is contained in:
Collin Jackson 2015-06-18 15:36:04 -07:00
parent 1422bb82aa
commit d44f8f2dbc
5 changed files with 91 additions and 60 deletions

View File

@ -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<Stock> _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);
}
}

View File

@ -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<Stock> _stocks = [];
Navigator _navigator;
void syncFields(StockHome source) {
navigator = source.navigator;
stocks = source.stocks;
}
Navigator navigator;
List<Stock> 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<Widget> 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)
),

View File

@ -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<Route> 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<Route> 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<Route> 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([

View File

@ -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();

View File

@ -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);
}
}