Commit 4b03a9ee authored by Hans Muller's avatar Hans Muller

Merge pull request #318 from HansMuller/stocks_demo

Add a persistent bottom sheet to the stocks demo
parents d6a0d92b 5755b15b
...@@ -81,7 +81,7 @@ class StocksAppState extends State<StocksApp> { ...@@ -81,7 +81,7 @@ class StocksAppState extends State<StocksApp> {
if (path.length != 3) if (path.length != 3)
return null; return null;
if (_stocks.containsKey(path[2])) if (_stocks.containsKey(path[2]))
return (RouteArguments args) => new StockSymbolViewer(stock: _stocks[path[2]]); return (RouteArguments args) => new StockSymbolPage(stock: _stocks[path[2]]);
return null; return null;
} }
return null; return null;
......
...@@ -20,6 +20,7 @@ class StockHome extends StatefulComponent { ...@@ -20,6 +20,7 @@ class StockHome extends StatefulComponent {
class StockHomeState extends State<StockHome> { class StockHomeState extends State<StockHome> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>(); final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
final GlobalKey<PlaceholderState> _bottomSheetPlaceholderKey = new GlobalKey<PlaceholderState>();
bool _isSearching = false; bool _isSearching = false;
String _searchQuery; String _searchQuery;
...@@ -188,13 +189,20 @@ class StockHomeState extends State<StockHome> { ...@@ -188,13 +189,20 @@ class StockHomeState extends State<StockHome> {
}); });
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
child: new StockSymbolViewer(stock: stock, showToolBar: false) child: new StockSymbolBottomSheet(stock: stock)
); );
}, },
onOpen: (Stock stock, Key arrowKey) { onOpen: (Stock stock, Key arrowKey) {
Set<Key> mostValuableKeys = new Set<Key>(); Set<Key> mostValuableKeys = new Set<Key>();
mostValuableKeys.add(arrowKey); mostValuableKeys.add(arrowKey);
Navigator.of(context).pushNamed('/stock/${stock.symbol}', mostValuableKeys: mostValuableKeys); Navigator.of(context).pushNamed('/stock/${stock.symbol}', mostValuableKeys: mostValuableKeys);
},
onShow: (Stock stock, Key arrowKey) {
showBottomSheet(
placeholderKey: _bottomSheetPlaceholderKey,
context: context,
child: new StockSymbolBottomSheet(stock: stock)
);
} }
); );
} }
...@@ -267,6 +275,7 @@ class StockHomeState extends State<StockHome> { ...@@ -267,6 +275,7 @@ class StockHomeState extends State<StockHome> {
toolBar: _isSearching ? buildSearchBar() : buildToolBar(), toolBar: _isSearching ? buildSearchBar() : buildToolBar(),
body: buildTabNavigator(), body: buildTabNavigator(),
snackBar: new Placeholder(key: _snackBarPlaceholderKey), snackBar: new Placeholder(key: _snackBarPlaceholderKey),
bottomSheet: new Placeholder(key: _bottomSheetPlaceholderKey),
floatingActionButton: buildFloatingActionButton() floatingActionButton: buildFloatingActionButton()
); );
} }
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
part of stocks; part of stocks;
class StockList extends StatelessComponent { class StockList extends StatelessComponent {
StockList({ Key key, this.stocks, this.onOpen, this.onAction }) : super(key: key); StockList({ Key key, this.stocks, this.onOpen, this.onShow, this.onAction }) : super(key: key);
final List<Stock> stocks; final List<Stock> stocks;
final StockRowActionCallback onOpen; final StockRowActionCallback onOpen;
final StockRowActionCallback onShow;
final StockRowActionCallback onAction; final StockRowActionCallback onAction;
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -19,6 +20,7 @@ class StockList extends StatelessComponent { ...@@ -19,6 +20,7 @@ class StockList extends StatelessComponent {
return new StockRow( return new StockRow(
stock: stock, stock: stock,
onPressed: onOpen, onPressed: onOpen,
onDoubleTap: onShow,
onLongPressed: onAction onLongPressed: onAction
); );
} }
......
...@@ -27,6 +27,7 @@ class StockRow extends StatelessComponent { ...@@ -27,6 +27,7 @@ class StockRow extends StatelessComponent {
StockRow({ StockRow({
Stock stock, Stock stock,
this.onPressed, this.onPressed,
this.onDoubleTap,
this.onLongPressed this.onLongPressed
}) : this.stock = stock, }) : this.stock = stock,
_arrowKey = new StockRowPartKey(stock, StockRowPartKind.arrow), _arrowKey = new StockRowPartKey(stock, StockRowPartKind.arrow),
...@@ -34,22 +35,15 @@ class StockRow extends StatelessComponent { ...@@ -34,22 +35,15 @@ class StockRow extends StatelessComponent {
final Stock stock; final Stock stock;
final StockRowActionCallback onPressed; final StockRowActionCallback onPressed;
final StockRowActionCallback onDoubleTap;
final StockRowActionCallback onLongPressed; final StockRowActionCallback onLongPressed;
final Key _arrowKey; final Key _arrowKey;
static const double kHeight = 79.0; static const double kHeight = 79.0;
GestureTapCallback _getTapHandler(StockRowActionCallback callback) { GestureTapCallback _getHandler(StockRowActionCallback callback) {
if (callback == null) return callback == null ? null : () => callback(stock, _arrowKey);
return null;
return () => callback(stock, _arrowKey);
}
GestureLongPressCallback _getLongPressHandler(StockRowActionCallback callback) {
if (callback == null)
return null;
return () => callback(stock, _arrowKey);
} }
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -58,8 +52,9 @@ class StockRow extends StatelessComponent { ...@@ -58,8 +52,9 @@ class StockRow extends StatelessComponent {
if (stock.percentChange > 0) if (stock.percentChange > 0)
changeInPrice = "+" + changeInPrice; changeInPrice = "+" + changeInPrice;
return new InkWell( return new InkWell(
onTap: _getTapHandler(onPressed), onTap: _getHandler(onPressed),
onLongPress: _getLongPressHandler(onLongPressed), onDoubleTap: _getHandler(onDoubleTap),
onLongPress: _getHandler(onLongPressed),
child: new Container( child: new Container(
padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0), padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0),
decoration: new BoxDecoration( decoration: new BoxDecoration(
......
...@@ -4,11 +4,10 @@ ...@@ -4,11 +4,10 @@
part of stocks; part of stocks;
class StockSymbolViewer extends StatelessComponent { class StockSymbolView extends StatelessComponent {
StockSymbolViewer({ this.stock, this.showToolBar: true }); StockSymbolView({ this.stock});
final Stock stock; final Stock stock;
final bool showToolBar;
Widget build(BuildContext context) { Widget build(BuildContext context) {
String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}"; String lastSale = "\$${stock.lastSale.toStringAsFixed(2)}";
...@@ -17,42 +16,42 @@ class StockSymbolViewer extends StatelessComponent { ...@@ -17,42 +16,42 @@ class StockSymbolViewer extends StatelessComponent {
changeInPrice = "+" + changeInPrice; changeInPrice = "+" + changeInPrice;
TextStyle headings = Theme.of(context).text.body2; TextStyle headings = Theme.of(context).text.body2;
Widget body = new Block(<Widget>[ return new Container(
new Container( padding: new EdgeDims.all(20.0),
margin: new EdgeDims.all(20.0), child: new Column(<Widget>[
child: new Card( new Row(<Widget>[
child: new Container( new Text(
padding: new EdgeDims.all(20.0), '${stock.symbol}',
child: new Column(<Widget>[ style: Theme.of(context).text.display2
new Row(<Widget>[ ),
new Text( new Hero(
'${stock.symbol}', tag: StockRowPartKind.arrow,
style: Theme.of(context).text.display2 turns: 2,
), child: new StockArrow(percentChange: stock.percentChange)
new Hero( ),
tag: StockRowPartKind.arrow, ],
turns: 2, justifyContent: FlexJustifyContent.spaceBetween
child: new StockArrow(percentChange: stock.percentChange) ),
), new Text('Last Sale', style: headings),
], new Text('$lastSale ($changeInPrice)'),
justifyContent: FlexJustifyContent.spaceBetween new Container(
), height: 8.0
new Text('Last Sale', style: headings), ),
new Text('$lastSale ($changeInPrice)'), new Text('Market Cap', style: headings),
new Container( new Text('${stock.marketCap}'),
height: 8.0 ],
), justifyContent: FlexJustifyContent.collapse
new Text('Market Cap', style: headings),
new Text('${stock.marketCap}'),
])
)
)
) )
]); );
}
}
class StockSymbolPage extends StatelessComponent {
StockSymbolPage({ this.stock });
if (!showToolBar) final Stock stock;
return body;
Widget build(BuildContext context) {
return new Scaffold( return new Scaffold(
toolBar: new ToolBar( toolBar: new ToolBar(
left: new IconButton( left: new IconButton(
...@@ -63,8 +62,28 @@ class StockSymbolViewer extends StatelessComponent { ...@@ -63,8 +62,28 @@ class StockSymbolViewer extends StatelessComponent {
), ),
center: new Text(stock.name) center: new Text(stock.name)
), ),
body: body body: new Block(<Widget>[
new Container(
margin: new EdgeDims.all(20.0),
child: new Card(child: new StockSymbolView(stock: stock))
)
])
); );
} }
}
class StockSymbolBottomSheet extends StatelessComponent {
StockSymbolBottomSheet({ this.stock });
final Stock stock;
Widget build(BuildContext context) {
return new Container(
child: new StockSymbolView(stock: stock),
padding: new EdgeDims.all(10.0),
decoration: new BoxDecoration(
border: new Border(top: new BorderSide(color: Colors.black26, width: 1.0))
)
);
}
} }
...@@ -28,6 +28,7 @@ class InkWell extends StatefulComponent { ...@@ -28,6 +28,7 @@ class InkWell extends StatefulComponent {
Key key, Key key,
this.child, this.child,
this.onTap, this.onTap,
this.onDoubleTap,
this.onLongPress, this.onLongPress,
this.onHighlightChanged, this.onHighlightChanged,
this.defaultColor, this.defaultColor,
...@@ -36,6 +37,7 @@ class InkWell extends StatefulComponent { ...@@ -36,6 +37,7 @@ class InkWell extends StatefulComponent {
final Widget child; final Widget child;
final GestureTapCallback onTap; final GestureTapCallback onTap;
final GestureTapCallback onDoubleTap;
final GestureLongPressCallback onLongPress; final GestureLongPressCallback onLongPress;
final _HighlightChangedCallback onHighlightChanged; final _HighlightChangedCallback onHighlightChanged;
final Color defaultColor; final Color defaultColor;
...@@ -54,6 +56,7 @@ class _InkWellState extends State<InkWell> { ...@@ -54,6 +56,7 @@ class _InkWellState extends State<InkWell> {
duration: _kInkWellHighlightFadeDuration, duration: _kInkWellHighlightFadeDuration,
child: new _InkSplashes( child: new _InkSplashes(
onTap: config.onTap, onTap: config.onTap,
onDoubleTap: config.onDoubleTap,
onLongPress: config.onLongPress, onLongPress: config.onLongPress,
onHighlightChanged: (bool value) { onHighlightChanged: (bool value) {
setState(() { setState(() {
...@@ -134,10 +137,12 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -134,10 +137,12 @@ class _RenderInkSplashes extends RenderProxyBox {
_RenderInkSplashes({ _RenderInkSplashes({
RenderBox child, RenderBox child,
GestureTapCallback onTap, GestureTapCallback onTap,
GestureTapCallback onDoubleTap,
GestureLongPressCallback onLongPress, GestureLongPressCallback onLongPress,
this.onHighlightChanged this.onHighlightChanged
}) : super(child) { }) : super(child) {
this.onTap = onTap; this.onTap = onTap;
this.onDoubleTap = onDoubleTap;
this.onLongPress = onLongPress; this.onLongPress = onLongPress;
} }
...@@ -148,6 +153,13 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -148,6 +153,13 @@ class _RenderInkSplashes extends RenderProxyBox {
_syncTapRecognizer(); _syncTapRecognizer();
} }
GestureTapCallback get onDoubleTap => _onDoubleTap;
GestureTapCallback _onDoubleTap;
void set onDoubleTap (GestureTapCallback value) {
_onDoubleTap = value;
_syncDoubleTapRecognizer();
}
GestureTapCallback get onLongPress => _onLongPress; GestureTapCallback get onLongPress => _onLongPress;
GestureTapCallback _onLongPress; GestureTapCallback _onLongPress;
void set onLongPress (GestureTapCallback value) { void set onLongPress (GestureTapCallback value) {
...@@ -161,6 +173,7 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -161,6 +173,7 @@ class _RenderInkSplashes extends RenderProxyBox {
_InkSplash _lastSplash; _InkSplash _lastSplash;
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
DoubleTapGestureRecognizer _doubleTap;
LongPressGestureRecognizer _longPress; LongPressGestureRecognizer _longPress;
void _removeSplash(_InkSplash splash) { void _removeSplash(_InkSplash splash) {
...@@ -170,8 +183,9 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -170,8 +183,9 @@ class _RenderInkSplashes extends RenderProxyBox {
} }
void handleEvent(InputEvent event, BoxHitTestEntry entry) { void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && (onTap != null || onLongPress != null)) { if (event.type == 'pointerdown' && (onTap != null || onDoubleTap != null || onLongPress != null)) {
_tap?.addPointer(event); _tap?.addPointer(event);
_doubleTap?.addPointer(event);
_longPress?.addPointer(event); _longPress?.addPointer(event);
} }
} }
...@@ -179,17 +193,19 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -179,17 +193,19 @@ class _RenderInkSplashes extends RenderProxyBox {
void attach() { void attach() {
super.attach(); super.attach();
_syncTapRecognizer(); _syncTapRecognizer();
_syncDoubleTapRecognizer();
_syncLongPressRecognizer(); _syncLongPressRecognizer();
} }
void detach() { void detach() {
_disposeTapRecognizer(); _disposeTapRecognizer();
_disposeDoubleTapRecognizer();
_disposeLongPressRecognizer(); _disposeLongPressRecognizer();
super.detach(); super.detach();
} }
void _syncTapRecognizer() { void _syncTapRecognizer() {
if (onTap == null && onLongPress == null) { if (onTap == null && doubleTap == null && onLongPress == null) {
_disposeTapRecognizer(); _disposeTapRecognizer();
} else { } else {
_tap ??= new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter) _tap ??= new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
...@@ -204,6 +220,20 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -204,6 +220,20 @@ class _RenderInkSplashes extends RenderProxyBox {
_tap = null; _tap = null;
} }
void _syncDoubleTapRecognizer() {
if (onDoubleTap == null) {
_disposeDoubleTapRecognizer();
} else {
_doubleTap ??= new DoubleTapGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
..onDoubleTap = _handleDoubleTap;
}
}
void _disposeDoubleTapRecognizer() {
_doubleTap?.dispose();
_doubleTap = null;
}
void _syncLongPressRecognizer() { void _syncLongPressRecognizer() {
if (onLongPress == null) { if (onLongPress == null) {
_disposeLongPressRecognizer(); _disposeLongPressRecognizer();
...@@ -241,6 +271,13 @@ class _RenderInkSplashes extends RenderProxyBox { ...@@ -241,6 +271,13 @@ class _RenderInkSplashes extends RenderProxyBox {
onHighlightChanged(false); onHighlightChanged(false);
} }
void _handleDoubleTap() {
_lastSplash?.confirm();
_lastSplash = null;
if (onDoubleTap != null)
onDoubleTap();
}
void _handleLongPress() { void _handleLongPress() {
_lastSplash?.confirm(); _lastSplash?.confirm();
_lastSplash = null; _lastSplash = null;
...@@ -269,18 +306,26 @@ class _InkSplashes extends OneChildRenderObjectWidget { ...@@ -269,18 +306,26 @@ class _InkSplashes extends OneChildRenderObjectWidget {
Key key, Key key,
Widget child, Widget child,
this.onTap, this.onTap,
this.onDoubleTap,
this.onLongPress, this.onLongPress,
this.onHighlightChanged this.onHighlightChanged
}) : super(key: key, child: child); }) : super(key: key, child: child);
final GestureTapCallback onTap; final GestureTapCallback onTap;
final GestureTapCallback onDoubleTap;
final GestureLongPressCallback onLongPress; final GestureLongPressCallback onLongPress;
final _HighlightChangedCallback onHighlightChanged; final _HighlightChangedCallback onHighlightChanged;
_RenderInkSplashes createRenderObject() => new _RenderInkSplashes(onTap: onTap, onLongPress: onLongPress, onHighlightChanged: onHighlightChanged); _RenderInkSplashes createRenderObject() => new _RenderInkSplashes(
onTap: onTap,
onDoubleTap: onDoubleTap,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged
);
void updateRenderObject(_RenderInkSplashes renderObject, _InkSplashes oldWidget) { void updateRenderObject(_RenderInkSplashes renderObject, _InkSplashes oldWidget) {
renderObject.onTap = onTap; renderObject.onTap = onTap;
renderObject.onDoubleTap = onDoubleTap;
renderObject.onLongPress = onLongPress; renderObject.onLongPress = onLongPress;
renderObject.onHighlightChanged = onHighlightChanged; renderObject.onHighlightChanged = onHighlightChanged;
} }
......
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