Commit ac6342ab authored by Hixie's avatar Hixie

Use the navigator to stack dialogs.

This removes the need to manually include the dialog builder in the main window's build() function.
It also removes the need to track if a dialog is visible.

Other changes:
- I made dialog.dart a bit more readable.
- I renamed transitionFinished to fullyOpaque since that's what actually matters.
- I made Routes track if they're opaque. Eventually this should probably be more configurable when creating the route.

Directions for Future Research:
- Use this for focus management somehow.
- The popup menu should use something like this.
- We should factor the following out into a showDialog() function that returns a future for the dialog's exit result:
    navigator.push(new DialogRoute(builder: (navigator, route) { ... }));
- Maybe navigator.pop() should take a value to return to that Future.
parent c6fe01ed
...@@ -68,10 +68,30 @@ class AddressBookApp extends App { ...@@ -68,10 +68,30 @@ class AddressBookApp extends App {
child: new Icon(type: 'image/photo_camera', size: 24), child: new Icon(type: 'image/photo_camera', size: 24),
backgroundColor: Theme.of(this).accentColor, backgroundColor: Theme.of(this).accentColor,
onPressed: () { onPressed: () {
showDialog = true; navigator.push(new DialogRoute(builder: (navigator, route) {
navigator.pushState(this, (_) { return new Dialog(
showDialog = false; title: new Text("Describe your picture"),
}); content: new ScrollableBlock([
new Field(inputKey: fillKey, icon: "editor/format_color_fill", placeholder: "Color"),
new Field(inputKey: emoticonKey, icon: "editor/insert_emoticon", placeholder: "Emotion"),
]),
onDismiss: navigator.pop,
actions: [
new FlatButton(
child: new Text('DISCARD'),
onPressed: () {
navigator.pop();
}
),
new FlatButton(
child: new Text('SAVE'),
onPressed: () {
navigator.pop();
}
),
]
);
}));
} }
); );
} }
...@@ -104,47 +124,15 @@ class AddressBookApp extends App { ...@@ -104,47 +124,15 @@ class AddressBookApp extends App {
); );
} }
bool showDialog = false;
Widget buildMain(Navigator navigator) { Widget buildMain(Navigator navigator) {
List<Widget> layers = [ return new Focus(
new Focus(
initialFocus: nameKey, initialFocus: nameKey,
child: new Scaffold( child: new Scaffold(
toolbar: buildToolBar(navigator), toolbar: buildToolBar(navigator),
body: buildBody(navigator), body: buildBody(navigator),
floatingActionButton: buildFloatingActionButton(navigator) floatingActionButton: buildFloatingActionButton(navigator)
) )
) );
];
if (showDialog) {
layers.add(new Focus(
initialFocus: fillKey,
child: new Dialog(
title: new Text("Describe your picture"),
content: new ScrollableBlock([
new Field(inputKey: fillKey, icon: "editor/format_color_fill", placeholder: "Color"),
new Field(inputKey: emoticonKey, icon: "editor/insert_emoticon", placeholder: "Emotion"),
]),
onDismiss: navigator.pop,
actions: [
new FlatButton(
child: new Text('DISCARD'),
onPressed: () {
navigator.pop();
}
),
new FlatButton(
child: new Text('SAVE'),
onPressed: () {
navigator.pop();
}
),
]
)
));
}
return new Stack(layers);
} }
NavigationState _navigationState; NavigationState _navigationState;
......
...@@ -18,8 +18,6 @@ class StockSettings extends StatefulComponent { ...@@ -18,8 +18,6 @@ class StockSettings extends StatefulComponent {
BackupMode backup; BackupMode backup;
SettingsUpdater updater; SettingsUpdater updater;
bool _showModeDialog = false;
void syncFields(StockSettings source) { void syncFields(StockSettings source) {
navigator = source.navigator; navigator = source.navigator;
optimism = source.optimism; optimism = source.optimism;
...@@ -47,10 +45,26 @@ class StockSettings extends StatefulComponent { ...@@ -47,10 +45,26 @@ class StockSettings extends StatefulComponent {
_handleOptimismChanged(false); _handleOptimismChanged(false);
break; break;
case StockMode.pessimistic: case StockMode.pessimistic:
_showModeDialog = true; navigator.push(new DialogRoute(builder: (navigator, route) {
navigator.pushState(this, (_) { return new Dialog(
_showModeDialog = false; title: new Text("Change mode?"),
}); content: new Text("Optimistic mode means everything is awesome. Are you sure you can handle that?"),
onDismiss: navigator.pop,
actions: [
new FlatButton(
child: new Text('NO THANKS'),
onPressed: navigator.pop
),
new FlatButton(
child: new Text('AGREE'),
onPressed: () {
_handleOptimismChanged(true);
navigator.pop();
}
),
]
);
}));
break; break;
} }
} }
...@@ -104,32 +118,9 @@ class StockSettings extends StatefulComponent { ...@@ -104,32 +118,9 @@ class StockSettings extends StatefulComponent {
} }
Widget build() { Widget build() {
List<Widget> layers = [ return new Scaffold(
new Scaffold(
toolbar: buildToolBar(), toolbar: buildToolBar(),
body: buildSettingsPane() body: buildSettingsPane()
) );
];
if (_showModeDialog) {
layers.add(new Dialog(
title: new Text("Change mode?"),
content: new Text("Optimistic mode means everything is awesome. Are you sure you can handle that?"),
onDismiss: navigator.pop,
actions: [
new FlatButton(
child: new Text('NO THANKS'),
onPressed: navigator.pop
),
new FlatButton(
child: new Text('AGREE'),
onPressed: () {
_handleOptimismChanged(true);
navigator.pop();
}
),
]
));
}
return new Stack(layers);
} }
} }
...@@ -46,14 +46,11 @@ class Dialog extends Component { ...@@ -46,14 +46,11 @@ class Dialog extends Component {
} }
Widget build() { Widget build() {
Container mask = new Container(
decoration: const BoxDecoration(
backgroundColor: const Color(0x7F000000)));
List<Widget> children = new List<Widget>(); List<Widget> dialogBody = new List<Widget>();
if (title != null) { if (title != null) {
children.add(new Padding( dialogBody.add(new Padding(
padding: new EdgeDims(24.0, 24.0, content == null ? 20.0 : 0.0, 24.0), padding: new EdgeDims(24.0, 24.0, content == null ? 20.0 : 0.0, 24.0),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: Theme.of(this).text.title, style: Theme.of(this).text.title,
...@@ -63,7 +60,7 @@ class Dialog extends Component { ...@@ -63,7 +60,7 @@ class Dialog extends Component {
} }
if (content != null) { if (content != null) {
children.add(new Padding( dialogBody.add(new Padding(
padding: const EdgeDims(20.0, 24.0, 24.0, 24.0), padding: const EdgeDims(20.0, 24.0, 24.0, 24.0),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: Theme.of(this).text.subhead, style: Theme.of(this).text.subhead,
...@@ -73,11 +70,15 @@ class Dialog extends Component { ...@@ -73,11 +70,15 @@ class Dialog extends Component {
} }
if (actions != null) if (actions != null)
children.add(new Flex(actions, justifyContent: FlexJustifyContent.end)); dialogBody.add(new Flex(actions, justifyContent: FlexJustifyContent.end));
return new Stack([ return new Stack([
new Listener( new Listener(
child: mask, child: new Container(
decoration: const BoxDecoration(
backgroundColor: const Color(0x7F000000)
)
),
onGestureTap: (_) => onDismiss() onGestureTap: (_) => onDismiss()
), ),
new Center( new Center(
...@@ -89,12 +90,13 @@ class Dialog extends Component { ...@@ -89,12 +90,13 @@ class Dialog extends Component {
level: 4, level: 4,
color: _color, color: _color,
child: new ShrinkWrapWidth( child: new ShrinkWrapWidth(
child: new ScrollableBlock(children) child: new ScrollableBlock(dialogBody)
) )
) )
) )
) )
) )
]); ]);
} }
} }
...@@ -9,22 +9,40 @@ import 'package:sky/widgets/animated_component.dart'; ...@@ -9,22 +9,40 @@ import 'package:sky/widgets/animated_component.dart';
import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/basic.dart';
import 'package:vector_math/vector_math.dart'; import 'package:vector_math/vector_math.dart';
typedef Widget Builder(Navigator navigator, RouteBase route); typedef Widget RouteBuilder(Navigator navigator, RouteBase route);
abstract class RouteBase { abstract class RouteBase {
Widget build(Navigator navigator, RouteBase route); Widget build(Navigator navigator, RouteBase route);
bool get isOpaque;
void popState() { } void popState() { }
} }
class Route extends RouteBase { class Route extends RouteBase {
Route({ this.name, this.builder }); Route({ this.name, this.builder });
final String name; final String name;
final Builder builder; final RouteBuilder builder;
Widget build(Navigator navigator, RouteBase route) => builder(navigator, route); Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
bool get isOpaque => true;
} }
class RouteState extends RouteBase { class DialogRoute extends RouteBase {
DialogRoute({ this.builder, this.callback });
final RouteBuilder builder;
Function callback;
Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
bool get isOpaque => false;
void popState() {
if (callback != null)
callback(this);
}
}
class RouteState extends RouteBase {
RouteState({ this.callback, this.route, this.owner }); RouteState({ this.callback, this.route, this.owner });
Function callback; Function callback;
...@@ -32,6 +50,7 @@ class RouteState extends RouteBase { ...@@ -32,6 +50,7 @@ class RouteState extends RouteBase {
StatefulComponent owner; StatefulComponent owner;
Widget build(Navigator navigator, RouteBase route) => null; Widget build(Navigator navigator, RouteBase route) => null;
bool get isOpaque => false;
void popState() { void popState() {
if (callback != null) if (callback != null)
...@@ -52,7 +71,7 @@ class Transition extends AnimatedComponent { ...@@ -52,7 +71,7 @@ class Transition extends AnimatedComponent {
this.onDismissed, this.onDismissed,
this.onCompleted, this.onCompleted,
this.interactive this.interactive
}) : super(key: key); }): super(key: key);
Widget content; Widget content;
TransitionDirection direction; TransitionDirection direction;
bool interactive; bool interactive;
...@@ -145,7 +164,7 @@ class Transition extends AnimatedComponent { ...@@ -145,7 +164,7 @@ class Transition extends AnimatedComponent {
class HistoryEntry { class HistoryEntry {
HistoryEntry({ this.route }); HistoryEntry({ this.route });
final RouteBase route; final RouteBase route;
bool transitionFinished = false; bool fullyOpaque = false;
// TODO(jackson): Keep track of the requested transition // TODO(jackson): Keep track of the requested transition
} }
...@@ -182,7 +201,7 @@ class NavigationState { ...@@ -182,7 +201,7 @@ class NavigationState {
if (historyIndex > 0) { if (historyIndex > 0) {
HistoryEntry entry = history[historyIndex]; HistoryEntry entry = history[historyIndex];
entry.route.popState(); entry.route.popState();
entry.transitionFinished = false; entry.fullyOpaque = false;
historyIndex--; historyIndex--;
} }
} }
...@@ -231,7 +250,7 @@ class Navigator extends StatefulComponent { ...@@ -231,7 +250,7 @@ class Navigator extends StatefulComponent {
List<Widget> visibleRoutes = new List<Widget>(); List<Widget> visibleRoutes = new List<Widget>();
for (int i = 0; i < state.history.length; i++) { for (int i = 0; i < state.history.length; i++) {
// Avoid building routes that are not visible // Avoid building routes that are not visible
if (i + 1 < state.history.length && state.history[i + 1].transitionFinished) if (i + 1 < state.history.length && state.history[i + 1].fullyOpaque)
continue; continue;
HistoryEntry historyEntry = state.history[i]; HistoryEntry historyEntry = state.history[i];
Widget content = historyEntry.route.build(this, historyEntry.route); Widget content = historyEntry.route.build(this, historyEntry.route);
...@@ -253,7 +272,7 @@ class Navigator extends StatefulComponent { ...@@ -253,7 +272,7 @@ class Navigator extends StatefulComponent {
}, },
onCompleted: () { onCompleted: () {
setState(() { setState(() {
historyEntry.transitionFinished = true; historyEntry.fullyOpaque = historyEntry.route.isOpaque;
}); });
} }
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment