Commit 179d41e6 authored by Hans Muller's avatar Hans Muller

Add CheckedPopupMenuitem, update the Stocks demo

parent c04b4c75
...@@ -94,7 +94,7 @@ class MenuDemoState extends State<MenuDemo> { ...@@ -94,7 +94,7 @@ class MenuDemoState extends State<MenuDemo> {
child: new Text('Context menu item one') child: new Text('Context menu item one')
), ),
new PopupMenuItem( new PopupMenuItem(
disabled: true, isDisabled: true,
child: new Text('A disabled menu item') child: new Text('A disabled menu item')
), ),
new PopupMenuItem( new PopupMenuItem(
...@@ -176,34 +176,26 @@ class MenuDemoState extends State<MenuDemo> { ...@@ -176,34 +176,26 @@ class MenuDemoState extends State<MenuDemo> {
right: new PopupMenuButton<String>( right: new PopupMenuButton<String>(
onSelected: showCheckedMenuSelections, onSelected: showCheckedMenuSelections,
items: <PopupMenuItem>[ items: <PopupMenuItem>[
new PopupMenuItem( new CheckedPopupMenuItem(
value: _checkedValue1, value: _checkedValue1,
child: new ListItem( isChecked: isChecked(_checkedValue1),
left: new Icon(icon: isChecked(_checkedValue1) ? 'action/done' : null), child: new Text(_checkedValue1)
primary: new Text(_checkedValue1)
)
), ),
new PopupMenuItem( new CheckedPopupMenuItem(
value: _checkedValue2, isDisabled: true,
child: new ListItem( isChecked: isChecked(_checkedValue2),
left: new Icon(icon: isChecked(_checkedValue2) ? 'action/done' : null), child: new Text(_checkedValue2)
primary: new Text(_checkedValue2)
)
), ),
new PopupMenuItem( new CheckedPopupMenuItem(
value: _checkedValue3, value: _checkedValue3,
child: new ListItem( isChecked: isChecked(_checkedValue3),
left: new Icon(icon: isChecked(_checkedValue3) ? 'action/done' : null), child: new Text(_checkedValue3)
primary: new Text(_checkedValue3)
)
), ),
new PopupMenuItem( new CheckedPopupMenuItem(
value: _checkedValue4, value: _checkedValue4,
child: new ListItem( isChecked: isChecked(_checkedValue4),
left: new Icon(icon: isChecked(_checkedValue4) ? 'action/done' : null), child: new Text(_checkedValue4)
primary: new Text(_checkedValue4) )
)
),
] ]
) )
) )
......
...@@ -6,6 +6,7 @@ material-design-icons: ...@@ -6,6 +6,7 @@ material-design-icons:
- name: action/account_balance - name: action/account_balance
- name: action/assessment - name: action/assessment
- name: action/backup - name: action/backup
- name: action/done
- name: action/help - name: action/help
- name: action/picture_in_picture - name: action/picture_in_picture
- name: action/search - name: action/search
......
...@@ -6,18 +6,50 @@ import 'dart:collection'; ...@@ -6,18 +6,50 @@ import 'dart:collection';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show debugDumpRenderTree, debugDumpLayerTree, debugDumpSemanticsTree; import 'package:flutter/rendering.dart' show debugDumpRenderTree, debugDumpLayerTree, debugDumpSemanticsTree;
import 'package:flutter/scheduler.dart' show timeDilation;
import 'stock_data.dart'; import 'stock_data.dart';
import 'stock_list.dart'; import 'stock_list.dart';
import 'stock_menu.dart';
import 'stock_strings.dart'; import 'stock_strings.dart';
import 'stock_symbol_viewer.dart'; import 'stock_symbol_viewer.dart';
import 'stock_types.dart'; import 'stock_types.dart';
typedef void ModeUpdater(StockMode mode); typedef void ModeUpdater(StockMode mode);
enum _StockMenuItem { autorefresh, refresh, speedUp, speedDown }
enum StockHomeTab { market, portfolio } enum StockHomeTab { market, portfolio }
class _NotImplementedDialog extends StatelessComponent {
Widget build(BuildContext context) {
return new Dialog(
title: new Text('Not Implemented'),
content: new Text('This feature has not yet been implemented.'),
actions: <Widget>[
new FlatButton(
child: new Row(
children: <Widget>[
new Icon(
icon: 'device/dvr',
size: IconSize.s18
),
new Container(
width: 8.0
),
new Text('DUMP APP TO CONSOLE'),
]
),
onPressed: () { debugDumpApp(); }
),
new FlatButton(
child: new Text('OH WELL'),
onPressed: () {
Navigator.pop(context, false);
}
)
]
);
}
}
class StockHome extends StatefulComponent { class StockHome extends StatefulComponent {
const StockHome(this.stocks, this.symbols, this.configuration, this.updater); const StockHome(this.stocks, this.symbols, this.configuration, this.updater);
...@@ -34,6 +66,7 @@ class StockHomeState extends State<StockHome> { ...@@ -34,6 +66,7 @@ class StockHomeState extends State<StockHome> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool _isSearching = false; bool _isSearching = false;
InputValue _searchQuery = InputValue.empty; InputValue _searchQuery = InputValue.empty;
bool _autorefresh = false;
void _handleSearchBegin() { void _handleSearchBegin() {
ModalRoute.of(context).addLocalHistoryEntry(new LocalHistoryEntry( ModalRoute.of(context).addLocalHistoryEntry(new LocalHistoryEntry(
...@@ -59,24 +92,31 @@ class StockHomeState extends State<StockHome> { ...@@ -59,24 +92,31 @@ class StockHomeState extends State<StockHome> {
}); });
} }
bool _autorefresh = false;
void _handleAutorefreshChanged(bool value) {
setState(() {
_autorefresh = value;
});
}
void _handleStockModeChange(StockMode value) { void _handleStockModeChange(StockMode value) {
if (config.updater != null) if (config.updater != null)
config.updater(config.configuration.copyWith(stockMode: value)); config.updater(config.configuration.copyWith(stockMode: value));
} }
void _handleMenuShow() { void _handleStockMenu(BuildContext context, _StockMenuItem value) {
showStockMenu( switch(value) {
context: context, case _StockMenuItem.autorefresh:
autorefresh: _autorefresh, setState(() {
onAutorefreshChanged: _handleAutorefreshChanged _autorefresh = !_autorefresh;
); });
break;
case _StockMenuItem.refresh:
showDialog(
context: context,
child: new _NotImplementedDialog()
);
break;
case _StockMenuItem.speedUp:
timeDilation /= 5.0;
break;
case _StockMenuItem.speedDown:
timeDilation *= 5.0;
break;
}
} }
Widget _buildDrawer(BuildContext context) { Widget _buildDrawer(BuildContext context) {
...@@ -176,10 +216,27 @@ class StockHomeState extends State<StockHome> { ...@@ -176,10 +216,27 @@ class StockHomeState extends State<StockHome> {
onPressed: _handleSearchBegin, onPressed: _handleSearchBegin,
tooltip: 'Search' tooltip: 'Search'
), ),
new IconButton( new PopupMenuButton<_StockMenuItem>(
icon: "navigation/more_vert", onSelected: (_StockMenuItem value) { _handleStockMenu(context, value); },
onPressed: _handleMenuShow, items: <PopupMenuItem>[
tooltip: 'Show menu' new CheckedPopupMenuItem(
value: _StockMenuItem.autorefresh,
isChecked: _autorefresh,
child: new Text('Autorefresh')
),
new PopupMenuItem(
value: _StockMenuItem.refresh,
child: new Text('Refresh')
),
new PopupMenuItem(
value: _StockMenuItem.speedUp,
child: new Text('Increase animation speed')
),
new PopupMenuItem(
value: _StockMenuItem.speedDown,
child: new Text('Decrease animation speed')
)
]
) )
], ],
tabBar: new TabBar<StockHomeTab>( tabBar: new TabBar<StockHomeTab>(
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui' as ui show window;
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
enum _MenuItems { autorefresh, autorefreshCheckbox, refresh, speedUp, speedDown }
const double _kMenuMargin = 16.0; // 24.0 on tablet
Future showStockMenu({BuildContext context, bool autorefresh, ValueChanged<bool> onAutorefreshChanged }) async {
StateSetter autorefreshStateSetter;
switch (await showMenu(
context: context,
position: new ModalPosition(
right: ui.window.padding.right + _kMenuMargin,
top: ui.window.padding.top + _kMenuMargin
),
items: <PopupMenuItem>[
new PopupMenuItem(
value: _MenuItems.autorefresh,
child: new Row(
children: <Widget>[
new Flexible(child: new Text('Autorefresh')),
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
autorefreshStateSetter = setState;
return new Checkbox(
value: autorefresh,
onChanged: (bool value) {
setState(() {
autorefresh = value;
});
Navigator.pop(context, _MenuItems.autorefreshCheckbox);
}
);
}
)
]
)
),
new PopupMenuItem(
value: _MenuItems.refresh,
child: new Text('Refresh')
),
new PopupMenuItem(
value: _MenuItems.speedUp,
child: new Text('Increase animation speed')
),
new PopupMenuItem(
value: _MenuItems.speedDown,
child: new Text('Decrease animation speed')
),
]
)) {
case _MenuItems.autorefresh:
autorefreshStateSetter(() {
autorefresh = !autorefresh;
});
continue autorefreshNotify;
autorefreshNotify:
case _MenuItems.autorefreshCheckbox:
onAutorefreshChanged(autorefresh);
break;
case _MenuItems.speedUp:
timeDilation /= 5.0;
break;
case _MenuItems.speedDown:
timeDilation *= 5.0;
break;
case _MenuItems.refresh:
await showDialog(
context: context,
child: new Dialog(
title: new Text('Not Implemented'),
content: new Text('This feature has not yet been implemented.'),
actions: <Widget>[
new FlatButton(
child: new Row(
children: <Widget>[
new Icon(
icon: 'device/dvr',
size: IconSize.s18
),
new Container(
width: 8.0
),
new Text('DUMP APP TO CONSOLE'),
]
),
onPressed: () { debugDumpApp(); }
),
new FlatButton(
child: new Text('OH WELL'),
onPressed: () {
Navigator.pop(context, false);
}
),
]
)
);
break;
default:
// menu was canceled.
}
}
...@@ -23,6 +23,7 @@ class ListItem extends StatelessComponent { ...@@ -23,6 +23,7 @@ class ListItem extends StatelessComponent {
this.right, this.right,
this.isThreeLine: false, this.isThreeLine: false,
this.isDense: false, this.isDense: false,
this.isDisabled: false,
this.onTap, this.onTap,
this.onLongPress this.onLongPress
}) : super(key: key) { }) : super(key: key) {
...@@ -36,11 +37,17 @@ class ListItem extends StatelessComponent { ...@@ -36,11 +37,17 @@ class ListItem extends StatelessComponent {
final Widget right; final Widget right;
final bool isThreeLine; final bool isThreeLine;
final bool isDense; final bool isDense;
final bool isDisabled;
final GestureTapCallback onTap; final GestureTapCallback onTap;
final GestureLongPressCallback onLongPress; final GestureLongPressCallback onLongPress;
TextStyle primaryTextStyle(BuildContext context) { TextStyle primaryTextStyle(BuildContext context) {
final TextStyle style = Theme.of(context).text.subhead; final ThemeData theme = Theme.of(context);
final TextStyle style = theme.text.subhead;
if (isDisabled) {
final Color color = theme.disabledColor;
return isDense ? style.copyWith(fontSize: 13.0, color: color) : style.copyWith(color: color);
}
return isDense ? style.copyWith(fontSize: 13.0) : style; return isDense ? style.copyWith(fontSize: 13.0) : style;
} }
...@@ -113,8 +120,8 @@ class ListItem extends StatelessComponent { ...@@ -113,8 +120,8 @@ class ListItem extends StatelessComponent {
} }
return new InkWell( return new InkWell(
onTap: onTap, onTap: isDisabled ? null : onTap,
onLongPress: onLongPress, onLongPress: isDisabled ? null : onLongPress,
child: new Container( child: new Container(
height: itemHeight, height: itemHeight,
padding: const EdgeDims.symmetric(horizontal: 16.0), padding: const EdgeDims.symmetric(horizontal: 16.0),
......
...@@ -6,8 +6,12 @@ import 'dart:async'; ...@@ -6,8 +6,12 @@ import 'dart:async';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'icon.dart';
import 'icon_button.dart'; import 'icon_button.dart';
import 'icon_theme.dart';
import 'icon_theme_data.dart';
import 'ink_well.dart'; import 'ink_well.dart';
import 'list_item.dart';
import 'material.dart'; import 'material.dart';
import 'theme.dart'; import 'theme.dart';
...@@ -21,27 +25,43 @@ const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; ...@@ -21,27 +25,43 @@ const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
const double _kMenuVerticalPadding = 8.0; const double _kMenuVerticalPadding = 8.0;
const double _kMenuWidthStep = 56.0; const double _kMenuWidthStep = 56.0;
const double _kMenuScreenPadding = 8.0; const double _kMenuScreenPadding = 8.0;
const double _kDisabledIconOpacity = 0.38;
class PopupMenuItem<T> extends StatelessComponent { class PopupMenuItem<T> extends StatelessComponent {
PopupMenuItem({ PopupMenuItem({
Key key, Key key,
this.value, this.value,
this.disabled: false, this.isDisabled: false,
this.hasDivider: false, this.hasDivider: false,
this.child this.child
}) : super(key: key); }) : super(key: key);
final T value; final T value;
final bool disabled; final bool isDisabled;
final bool hasDivider; final bool hasDivider;
final Widget child; final Widget child;
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
TextStyle style = theme.text.subhead; TextStyle style = theme.text.subhead;
if (disabled) if (isDisabled)
style = style.copyWith(color: theme.disabledColor); style = style.copyWith(color: theme.disabledColor);
Widget item = new DefaultTextStyle(
style: style,
child: new Baseline(
baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom,
child: child
)
);
if (isDisabled) {
final bool isDark = theme.brightness == ThemeBrightness.dark;
item = new IconTheme(
data: new IconThemeData(opacity: isDark ? 0.5 : 0.38),
child: item
);
}
return new MergeSemantics( return new MergeSemantics(
child: new Container( child: new Container(
height: _kMenuItemHeight, height: _kMenuItemHeight,
...@@ -49,18 +69,31 @@ class PopupMenuItem<T> extends StatelessComponent { ...@@ -49,18 +69,31 @@ class PopupMenuItem<T> extends StatelessComponent {
decoration: !hasDivider ? null : new BoxDecoration( decoration: !hasDivider ? null : new BoxDecoration(
border: new Border(bottom: new BorderSide(color: theme.dividerColor)) border: new Border(bottom: new BorderSide(color: theme.dividerColor))
), ),
child: new DefaultTextStyle( child: item
style: style,
child: new Baseline(
baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom,
child: child
)
)
) )
); );
} }
} }
class CheckedPopupMenuItem<T> extends PopupMenuItem<T> {
CheckedPopupMenuItem({
Key key,
T value,
isChecked: false,
bool isDisabled: false,
Widget child
}) : super(
key: key,
value: value,
isDisabled: isDisabled,
child: new ListItem(
isDisabled: isDisabled,
left: new Icon(icon: isChecked ? 'action/done' : null),
primary: child
)
);
}
class _PopupMenu<T> extends StatelessComponent { class _PopupMenu<T> extends StatelessComponent {
_PopupMenu({ _PopupMenu({
Key key, Key key,
...@@ -80,7 +113,7 @@ class _PopupMenu<T> extends StatelessComponent { ...@@ -80,7 +113,7 @@ class _PopupMenu<T> extends StatelessComponent {
parent: route.animation, parent: route.animation,
curve: new Interval(start, end) curve: new Interval(start, end)
); );
final bool disabled = route.items[i].disabled; final bool isDisabled = route.items[i].isDisabled;
Widget item = route.items[i]; Widget item = route.items[i];
if (route.initialValue != null && route.initialValue == route.items[i].value) { if (route.initialValue != null && route.initialValue == route.items[i].value) {
item = new Container( item = new Container(
...@@ -91,7 +124,7 @@ class _PopupMenu<T> extends StatelessComponent { ...@@ -91,7 +124,7 @@ class _PopupMenu<T> extends StatelessComponent {
children.add(new FadeTransition( children.add(new FadeTransition(
opacity: opacity, opacity: opacity,
child: new InkWell( child: new InkWell(
onTap: disabled ? null : () { Navigator.pop(context, route.items[i].value); }, onTap: isDisabled ? null : () { Navigator.pop(context, route.items[i].value); },
child: item child: item
) )
)); ));
...@@ -298,7 +331,7 @@ class _PopupMenuButtonState<T> extends State<PopupMenuButton<T>> { ...@@ -298,7 +331,7 @@ class _PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
) )
) )
.then((T value) { .then((T value) {
if (config.onSelected != null) if (value != null && config.onSelected != null)
config.onSelected(value); config.onSelected(value);
}); });
} }
......
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