Unverified Commit 231170a7 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Replace child parameter with builder on showDialog (#15303)

* replace child parameter with builder on showDialog

* change builder parameter to WidgetBuilder

* mark child as deprecated and expand documentation to cover this and how builder should be used

* tidy comments and address some feedback

* phrasing

* move space to prev line and add //ignore comments for deprecated member use

* address comments and fix it's its

* update code samples

* adds semicolon to code snippets
parent 9a8b4602
...@@ -18,8 +18,8 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> { ...@@ -18,8 +18,8 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> {
void showDemoDialog<T>({ BuildContext context, Widget child }) { void showDemoDialog<T>({ BuildContext context, Widget child }) {
showDialog<T>( showDialog<T>(
context: context, context: context,
child: child,
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) => child,
) )
.then<Null>((T value) { // The value passed to Navigator.pop() or null. .then<Null>((T value) { // The value passed to Navigator.pop() or null.
if (value != null) { if (value != null) {
......
...@@ -68,7 +68,7 @@ class DialogDemoState extends State<DialogDemo> { ...@@ -68,7 +68,7 @@ class DialogDemoState extends State<DialogDemo> {
void showDemoDialog<T>({ BuildContext context, Widget child }) { void showDemoDialog<T>({ BuildContext context, Widget child }) {
showDialog<T>( showDialog<T>(
context: context, context: context,
child: child, builder: (BuildContext context) => child,
) )
.then<Null>((T value) { // The value passed to Navigator.pop() or null. .then<Null>((T value) { // The value passed to Navigator.pop() or null.
if (value != null) { if (value != null) {
......
...@@ -233,17 +233,19 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin { ...@@ -233,17 +233,19 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
void _onOtherAccountsTap(BuildContext context) { void _onOtherAccountsTap(BuildContext context) {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
title: const Text('Account switching not implemented.'), return new AlertDialog(
actions: <Widget>[ title: const Text('Account switching not implemented.'),
new FlatButton( actions: <Widget>[
child: const Text('OK'), new FlatButton(
onPressed: () { child: const Text('OK'),
Navigator.of(context).pop(); onPressed: () {
}, Navigator.of(context).pop();
), },
], ),
), ],
);
},
); );
} }
} }
...@@ -116,26 +116,28 @@ class FullScreenDialogDemoState extends State<FullScreenDialogDemo> { ...@@ -116,26 +116,28 @@ class FullScreenDialogDemoState extends State<FullScreenDialogDemo> {
return await showDialog<bool>( return await showDialog<bool>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
content: new Text( return new AlertDialog(
'Discard new event?', content: new Text(
style: dialogTextStyle 'Discard new event?',
), style: dialogTextStyle
actions: <Widget>[
new FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page.
}
), ),
new FlatButton( actions: <Widget>[
child: const Text('DISCARD'), new FlatButton(
onPressed: () { child: const Text('CANCEL'),
Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again. onPressed: () {
} Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page.
) }
] ),
) new FlatButton(
child: const Text('DISCARD'),
onPressed: () {
Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again.
}
)
],
);
},
) ?? false; ) ?? false;
} }
......
...@@ -56,15 +56,19 @@ class _PersistentBottomSheetDemoState extends State<PersistentBottomSheetDemo> { ...@@ -56,15 +56,19 @@ class _PersistentBottomSheetDemoState extends State<PersistentBottomSheetDemo> {
void _showMessage() { void _showMessage() {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
content: const Text('You tapped the floating action button.'), return new AlertDialog(
actions: <Widget>[ content: const Text('You tapped the floating action button.'),
new FlatButton( actions: <Widget>[
onPressed: () { Navigator.pop(context); }, new FlatButton(
child: const Text('OK') onPressed: () {
) Navigator.pop(context);
] },
) child: const Text('OK')
)
],
);
},
); );
} }
......
...@@ -85,20 +85,22 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -85,20 +85,22 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
return await showDialog<bool>( return await showDialog<bool>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
title: const Text('This form has errors'), return new AlertDialog(
content: const Text('Really leave this form?'), title: const Text('This form has errors'),
actions: <Widget> [ content: const Text('Really leave this form?'),
new FlatButton( actions: <Widget> [
child: const Text('YES'), new FlatButton(
onPressed: () { Navigator.of(context).pop(true); }, child: const Text('YES'),
), onPressed: () { Navigator.of(context).pop(true); },
new FlatButton( ),
child: const Text('NO'), new FlatButton(
onPressed: () { Navigator.of(context).pop(false); }, child: const Text('NO'),
), onPressed: () { Navigator.of(context).pop(false); },
], ),
), ],
);
},
) ?? false; ) ?? false;
} }
......
...@@ -41,13 +41,13 @@ class UpdaterState extends State<Updater> { ...@@ -41,13 +41,13 @@ class UpdaterState extends State<Updater> {
final String updateUrl = await widget.updateUrlFetcher(); final String updateUrl = await widget.updateUrlFetcher();
if (updateUrl != null) { if (updateUrl != null) {
final bool wantsUpdate = await showDialog(context: context, child: _buildDialog()); final bool wantsUpdate = await showDialog(context: context, builder: _buildDialog);
if (wantsUpdate != null && wantsUpdate) if (wantsUpdate != null && wantsUpdate)
launch(updateUrl); launch(updateUrl);
} }
} }
Widget _buildDialog() { Widget _buildDialog(BuildContext _) {
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
final TextStyle dialogTextStyle = final TextStyle dialogTextStyle =
theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color); theme.textTheme.subhead.copyWith(color: theme.textTheme.caption.color);
......
...@@ -95,7 +95,7 @@ class StockHomeState extends State<StockHome> { ...@@ -95,7 +95,7 @@ class StockHomeState extends State<StockHome> {
case _StockMenuItem.refresh: case _StockMenuItem.refresh:
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new _NotImplementedDialog() builder: (BuildContext context) => new _NotImplementedDialog(),
); );
break; break;
case _StockMenuItem.speedUp: case _StockMenuItem.speedUp:
......
...@@ -67,24 +67,26 @@ class StockSettingsState extends State<StockSettings> { ...@@ -67,24 +67,26 @@ class StockSettingsState extends State<StockSettings> {
case StockMode.pessimistic: case StockMode.pessimistic:
showDialog<bool>( showDialog<bool>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
title: const Text('Change mode?'), return new AlertDialog(
content: const Text('Optimistic mode means everything is awesome. Are you sure you can handle that?'), title: const Text('Change mode?'),
actions: <Widget>[ content: const Text('Optimistic mode means everything is awesome. Are you sure you can handle that?'),
new FlatButton( actions: <Widget>[
child: const Text('NO THANKS'), new FlatButton(
onPressed: () { child: const Text('NO THANKS'),
Navigator.pop(context, false); onPressed: () {
} Navigator.pop(context, false);
), }
new FlatButton( ),
child: const Text('AGREE'), new FlatButton(
onPressed: () { child: const Text('AGREE'),
Navigator.pop(context, true); onPressed: () {
} Navigator.pop(context, true);
), }
] ),
) ],
);
},
).then<void>(_handleOptimismChanged); ).then<void>(_handleOptimismChanged);
break; break;
} }
......
...@@ -153,13 +153,15 @@ void showAboutDialog({ ...@@ -153,13 +153,15 @@ void showAboutDialog({
}) { }) {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new AboutDialog( builder: (BuildContext context) {
applicationName: applicationName, return new AboutDialog(
applicationVersion: applicationVersion, applicationName: applicationName,
applicationIcon: applicationIcon, applicationVersion: applicationVersion,
applicationLegalese: applicationLegalese, applicationIcon: applicationIcon,
children: children applicationLegalese: applicationLegalese,
) children: children,
);
}
); );
} }
......
...@@ -1042,6 +1042,6 @@ Future<DateTime> showDatePicker({ ...@@ -1042,6 +1042,6 @@ Future<DateTime> showDatePicker({
return await showDialog<DateTime>( return await showDialog<DateTime>(
context: context, context: context,
child: child, builder: (BuildContext context) => child,
); );
} }
...@@ -96,25 +96,27 @@ class Dialog extends StatelessWidget { ...@@ -96,25 +96,27 @@ class Dialog extends StatelessWidget {
/// return showDialog<Null>( /// return showDialog<Null>(
/// context: context, /// context: context,
/// barrierDismissible: false, // user must tap button! /// barrierDismissible: false, // user must tap button!
/// child: new AlertDialog( /// builder: (BuildContext context) {
/// title: new Text('Rewind and remember'), /// return new AlertDialog(
/// content: new SingleChildScrollView( /// title: new Text('Rewind and remember'),
/// child: new ListBody( /// content: new SingleChildScrollView(
/// children: <Widget>[ /// child: new ListBody(
/// new Text('You will never be satisfied.'), /// children: <Widget>[
/// new Text('You\’re like me. I’m never satisfied.'), /// new Text('You will never be satisfied.'),
/// ], /// new Text('You\’re like me. I’m never satisfied.'),
/// ],
/// ),
/// ), /// ),
/// ), /// actions: <Widget>[
/// actions: <Widget>[ /// new FlatButton(
/// new FlatButton( /// child: new Text('Regret'),
/// child: new Text('Regret'), /// onPressed: () {
/// onPressed: () { /// Navigator.of(context).pop();
/// Navigator.of(context).pop(); /// },
/// }, /// ),
/// ), /// ],
/// ], /// );
/// ), /// },
/// ); /// );
/// } /// }
/// ``` /// ```
...@@ -301,19 +303,21 @@ class SimpleDialogOption extends StatelessWidget { ...@@ -301,19 +303,21 @@ class SimpleDialogOption extends StatelessWidget {
/// Future<Null> _askedToLead() async { /// Future<Null> _askedToLead() async {
/// switch (await showDialog<Department>( /// switch (await showDialog<Department>(
/// context: context, /// context: context,
/// child: new SimpleDialog( /// builder: (BuildContext context) {
/// title: const Text('Select assignment'), /// return new SimpleDialog(
/// children: <Widget>[ /// title: const Text('Select assignment'),
/// new SimpleDialogOption( /// children: <Widget>[
/// onPressed: () { Navigator.pop(context, Department.treasury); }, /// new SimpleDialogOption(
/// child: const Text('Treasury department'), /// onPressed: () { Navigator.pop(context, Department.treasury); },
/// ), /// child: const Text('Treasury department'),
/// new SimpleDialogOption( /// ),
/// onPressed: () { Navigator.pop(context, Department.state); }, /// new SimpleDialogOption(
/// child: const Text('State department'), /// onPressed: () { Navigator.pop(context, Department.state); },
/// ), /// child: const Text('State department'),
/// ], /// ),
/// ), /// ],
/// );
/// }
/// )) { /// )) {
/// case Department.treasury: /// case Department.treasury:
/// // Let's go. /// // Let's go.
...@@ -457,13 +461,18 @@ class _DialogRoute<T> extends PopupRoute<T> { ...@@ -457,13 +461,18 @@ class _DialogRoute<T> extends PopupRoute<T> {
/// Displays a dialog above the current contents of the app. /// Displays a dialog above the current contents of the app.
/// ///
/// This function typically receives a [Dialog] widget as its child argument. /// This function takes a `builder` which typically builds a [Dialog] widget.
/// Content below the dialog is dimmed with a [ModalBarrier]. /// Content below the dialog is dimmed with a [ModalBarrier]. This widget does
/// not share a context with the location that `showDialog` is originally
/// called from. Use a [StatefulBuilder] or a custom [StatefulWidget] if the
/// dialog needs to update dynamically.
/// ///
/// The `context` argument is used to look up the [Navigator] and [Theme] for /// The `context` argument is used to look up the [Navigator] and [Theme] for
/// the dialog. It is only used when the method is called. Its corresponding /// the dialog. It is only used when the method is called. Its corresponding
/// widget can be safely removed from the tree before the dialog is closed. /// widget can be safely removed from the tree before the dialog is closed.
/// ///
/// The `child` argument is deprecated, and should be replaced with `builder`.
///
/// Returns a [Future] that resolves to the value (if any) that was passed to /// Returns a [Future] that resolves to the value (if any) that was passed to
/// [Navigator.pop] when the dialog was closed. /// [Navigator.pop] when the dialog was closed.
/// ///
...@@ -481,10 +490,16 @@ class _DialogRoute<T> extends PopupRoute<T> { ...@@ -481,10 +490,16 @@ class _DialogRoute<T> extends PopupRoute<T> {
Future<T> showDialog<T>({ Future<T> showDialog<T>({
@required BuildContext context, @required BuildContext context,
bool barrierDismissible: true, bool barrierDismissible: true,
@required Widget child, @Deprecated(
'Instead of using the "child" argument, return the child from a closure '
'provided to the "builder" argument. This will ensure that the BuildContext '
'is appropriate for widgets built in the dialog.'
) Widget child,
WidgetBuilder builder,
}) { }) {
assert(child == null || builder == null); // ignore: deprecated_member_use
return Navigator.of(context, rootNavigator: true).push(new _DialogRoute<T>( return Navigator.of(context, rootNavigator: true).push(new _DialogRoute<T>(
child: child, child: child ?? new Builder(builder: builder), // ignore: deprecated_member_use
theme: Theme.of(context, shadowThemeOnly: true), theme: Theme.of(context, shadowThemeOnly: true),
barrierDismissible: barrierDismissible, barrierDismissible: barrierDismissible,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
......
...@@ -1645,7 +1645,7 @@ Future<TimeOfDay> showTimePicker({ ...@@ -1645,7 +1645,7 @@ Future<TimeOfDay> showTimePicker({
return await showDialog<TimeOfDay>( return await showDialog<TimeOfDay>(
context: context, context: context,
child: new _TimePickerDialog(initialTime: initialTime), builder: (BuildContext context) => new _TimePickerDialog(initialTime: initialTime),
); );
} }
......
...@@ -19,23 +19,25 @@ void main() { ...@@ -19,23 +19,25 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new CupertinoAlertDialog( builder: (BuildContext context) {
title: const Text('The title'), return new CupertinoAlertDialog(
content: const Text('The content'), title: const Text('The title'),
actions: <Widget>[ content: const Text('The content'),
const CupertinoDialogAction( actions: <Widget>[
child: const Text('Cancel'), const CupertinoDialogAction(
), child: const Text('Cancel'),
new CupertinoDialogAction( ),
isDestructiveAction: true, new CupertinoDialogAction(
onPressed: () { isDestructiveAction: true,
didDelete = true; onPressed: () {
Navigator.pop(context); didDelete = true;
}, Navigator.pop(context);
child: const Text('Delete'), },
), child: const Text('Delete'),
], ),
), ],
);
},
); );
}, },
child: const Text('Go'), child: const Text('Go'),
...@@ -110,7 +112,7 @@ void main() { ...@@ -110,7 +112,7 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new Builder(builder: (BuildContext context) { builder: (BuildContext context) {
return new MediaQuery( return new MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0), data: MediaQuery.of(context).copyWith(textScaleFactor: 3.0),
child: new CupertinoAlertDialog( child: new CupertinoAlertDialog(
...@@ -128,7 +130,7 @@ void main() { ...@@ -128,7 +130,7 @@ void main() {
scrollController: scrollController, scrollController: scrollController,
), ),
); );
}), },
); );
}, },
child: const Text('Go'), child: const Text('Go'),
......
...@@ -23,21 +23,23 @@ void main() { ...@@ -23,21 +23,23 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
content: new Container( return new AlertDialog(
height: 5000.0, content: new Container(
width: 300.0, height: 5000.0,
color: Colors.green[500], width: 300.0,
), color: Colors.green[500],
actions: <Widget>[ ),
new FlatButton( actions: <Widget>[
onPressed: () { new FlatButton(
didPressOk = true; onPressed: () {
}, didPressOk = true;
child: const Text('OK') },
) child: const Text('OK')
] )
) ],
);
},
); );
} }
) )
...@@ -71,11 +73,13 @@ void main() { ...@@ -71,11 +73,13 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: const AlertDialog( builder: (BuildContext context) {
title: const Text('Title'), return const AlertDialog(
content: const Text('Y'), title: const Text('Title'),
actions: const <Widget>[ ], content: const Text('Y'),
), actions: const <Widget>[ ],
);
},
); );
}, },
), ),
...@@ -116,20 +120,22 @@ void main() { ...@@ -116,20 +120,22 @@ void main() {
final Future<int> result = showDialog( final Future<int> result = showDialog(
context: context, context: context,
child: new SimpleDialog( builder: (BuildContext context) {
title: const Text('Title'), return new SimpleDialog(
children: <Widget>[ title: const Text('Title'),
new SimpleDialogOption( children: <Widget>[
onPressed: () { new SimpleDialogOption(
Navigator.pop(context, 42); onPressed: () {
}, Navigator.pop(context, 42);
child: const Text('First option'), },
), child: const Text('First option'),
const SimpleDialogOption( ),
child: const Text('Second option'), const SimpleDialogOption(
), child: const Text('Second option'),
], ),
), ],
);
},
); );
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
...@@ -157,12 +163,14 @@ void main() { ...@@ -157,12 +163,14 @@ void main() {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new Container( builder: (BuildContext context) {
width: 100.0, return new Container(
height: 100.0, width: 100.0,
alignment: Alignment.center, height: 100.0,
child: const Text('Dialog1'), alignment: Alignment.center,
), child: const Text('Dialog1'),
);
},
); );
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
...@@ -177,12 +185,14 @@ void main() { ...@@ -177,12 +185,14 @@ void main() {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
child: new Container( builder: (BuildContext context) {
width: 100.0, return new Container(
height: 100.0, width: 100.0,
alignment: Alignment.center, height: 100.0,
child: const Text('Dialog2'), alignment: Alignment.center,
), child: const Text('Dialog2'),
);
},
); );
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
...@@ -219,7 +229,9 @@ void main() { ...@@ -219,7 +229,9 @@ void main() {
const String alertText = 'A button in an overlay alert'; const String alertText = 'A button in an overlay alert';
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: const AlertDialog(title: const Text(alertText)), builder: (BuildContext context) {
return const AlertDialog(title: const Text(alertText));
},
); );
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
...@@ -260,12 +272,10 @@ void main() { ...@@ -260,12 +272,10 @@ void main() {
showDialog<Null>( showDialog<Null>(
context: outerContext, context: outerContext,
barrierDismissible: false, barrierDismissible: false,
child: new Builder( builder: (BuildContext context) {
builder: (BuildContext context) { dialogContext = context;
dialogContext = context; return new Container();
return new Container(); },
},
),
); );
await tester.pump(); await tester.pump();
......
...@@ -110,7 +110,7 @@ void main() { ...@@ -110,7 +110,7 @@ void main() {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: const SimpleDialog(title: const Text('Dialog')), builder: (BuildContext context) => const SimpleDialog(title: const Text('Dialog')),
); );
await tester.pump(); await tester.pump();
......
...@@ -200,7 +200,7 @@ void main() { ...@@ -200,7 +200,7 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: const Text('dialog'), builder: (BuildContext context) => const Text('dialog'),
); );
}, },
child: const Text('SHOW'), child: const Text('SHOW'),
...@@ -232,12 +232,14 @@ void main() { ...@@ -232,12 +232,14 @@ void main() {
onTap: () { onTap: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: const Scaffold( builder: (BuildContext context) {
body: const SizedBox( return const Scaffold(
width: 200.0, body: const SizedBox(
height: 200.0, width: 200.0,
), height: 200.0,
) ),
);
},
); );
}, },
child: const Text('SHOW'), child: const Text('SHOW'),
......
...@@ -86,7 +86,7 @@ void main() { ...@@ -86,7 +86,7 @@ void main() {
onPressed: () { onPressed: () {
showDialog<Null>( showDialog<Null>(
context: context, context: context,
child: new SamplePage(), builder: (BuildContext context) => new SamplePage(),
); );
}, },
), ),
...@@ -185,18 +185,20 @@ void main() { ...@@ -185,18 +185,20 @@ void main() {
Future<bool> showYesNoAlert(BuildContext context) { Future<bool> showYesNoAlert(BuildContext context) {
return showDialog<bool>( return showDialog<bool>(
context: context, context: context,
child: new AlertDialog( builder: (BuildContext context) {
actions: <Widget> [ return new AlertDialog(
new FlatButton( actions: <Widget> [
child: const Text('YES'), new FlatButton(
onPressed: () { Navigator.of(context).pop(true); }, child: const Text('YES'),
), onPressed: () { Navigator.of(context).pop(true); },
new FlatButton( ),
child: const Text('NO'), new FlatButton(
onPressed: () { Navigator.of(context).pop(false); }, child: const Text('NO'),
), onPressed: () { Navigator.of(context).pop(false); },
], ),
), ],
);
},
); );
} }
......
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