Unverified Commit e4b574d3 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Cupertino Dialog Changes (#17676)

This replaces abandoned PR #14824 by @ekbiker, and gives it some love.
parent 89d99f6d
...@@ -15,17 +15,19 @@ class CupertinoDialogDemo extends StatefulWidget { ...@@ -15,17 +15,19 @@ class CupertinoDialogDemo extends StatefulWidget {
class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> { class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showDemoDialog<T>({ BuildContext context, Widget child }) { void showDemoDialog<T>({BuildContext context, Widget child}) {
showDialog<T>( showDialog<T>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) => child, builder: (BuildContext context) => child,
) ).then<void>((T value) {
.then<void>((T value) { // The value passed to Navigator.pop() or null. // The value passed to Navigator.pop() or null.
if (value != null) { if (value != null) {
_scaffoldKey.currentState.showSnackBar(new SnackBar( _scaffoldKey.currentState.showSnackBar(
content: new Text('You selected: $value') new SnackBar(
)); content: new Text('You selected: $value'),
),
);
} }
}); });
} }
...@@ -39,7 +41,7 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> { ...@@ -39,7 +41,7 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> {
), ),
body: new ListView( body: new ListView(
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0), padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0),
children: <Widget> [ children: <Widget>[
new CupertinoButton( new CupertinoButton(
child: const Text('Alert'), child: const Text('Alert'),
color: CupertinoColors.activeBlue, color: CupertinoColors.activeBlue,
...@@ -47,19 +49,23 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> { ...@@ -47,19 +49,23 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> {
showDemoDialog<String>( showDemoDialog<String>(
context: context, context: context,
child: new CupertinoAlertDialog( child: new CupertinoAlertDialog(
content: const Text('Discard draft?'), title: const Text('Discard draft?'),
actions: <Widget>[ actions: <Widget>[
new CupertinoDialogAction( new CupertinoDialogAction(
child: const Text('Discard'), child: const Text('Discard'),
isDestructiveAction: true, isDestructiveAction: true,
onPressed: () { Navigator.pop(context, 'Discard'); } onPressed: () {
Navigator.pop(context, 'Discard');
},
), ),
new CupertinoDialogAction( new CupertinoDialogAction(
child: const Text('Cancel'), child: const Text('Cancel'),
isDefaultAction: true, isDefaultAction: true,
onPressed: () { Navigator.pop(context, 'Cancel'); } onPressed: () {
Navigator.pop(context, 'Cancel');
},
), ),
] ],
), ),
); );
}, },
...@@ -74,26 +80,123 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> { ...@@ -74,26 +80,123 @@ class _CupertinoDialogDemoState extends State<CupertinoDialogDemo> {
context: context, context: context,
child: new CupertinoAlertDialog( child: new CupertinoAlertDialog(
title: const Text('Allow "Maps" to access your location while you are using the app?'), title: const Text('Allow "Maps" to access your location while you are using the app?'),
content: const Text( content: const Text('Your current location will be displayed on the map and used '
'Your current location will be displayed on the map and used for directions, ' 'for directions, nearby search results, and estimated travel times.'),
'nearby search results, and estimated travel times.'
),
actions: <Widget>[ actions: <Widget>[
new CupertinoDialogAction( new CupertinoDialogAction(
child: const Text('Don\'t Allow'), child: const Text('Don\'t Allow'),
onPressed: () { Navigator.pop(context, 'Disallow'); } onPressed: () {
Navigator.pop(context, 'Disallow');
},
), ),
new CupertinoDialogAction( new CupertinoDialogAction(
child: const Text('Allow'), child: const Text('Allow'),
onPressed: () { Navigator.pop(context, 'Allow'); } onPressed: () {
Navigator.pop(context, 'Allow');
},
), ),
] ],
), ),
); );
}, },
), ),
const Padding(padding: const EdgeInsets.all(8.0)),
new CupertinoButton(
child: const Text('Alert with Buttons'),
color: CupertinoColors.activeBlue,
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
onPressed: () {
showDemoDialog<String>(
context: context,
child: const CupertinoDessertDialog(
title: const Text('Select Favorite Dessert'),
content: const Text('Please select your favorite type of dessert from the '
'list below. Your selection will be used to customize the suggested '
'list of eateries in your area.'),
),
);
},
),
const Padding(padding: const EdgeInsets.all(8.0)),
new CupertinoButton(
child: const Text('Alert Buttons Only'),
color: CupertinoColors.activeBlue,
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
onPressed: () {
showDemoDialog<String>(
context: context,
child: const CupertinoDessertDialog(),
);
},
),
], ],
), ),
); );
} }
} }
class CupertinoDessertDialog extends StatelessWidget {
const CupertinoDessertDialog({Key key, this.title, this.content}) : super(key: key);
final Widget title;
final Widget content;
@override
Widget build(BuildContext context) {
return new CupertinoAlertDialog(
title: title,
content: content,
actions: <Widget>[
new CupertinoDialogAction(
child: const Text('Cheesecake'),
onPressed: () {
Navigator.pop(context, 'Cheesecake');
},
),
new CupertinoDialogAction(
child: const Text('Tiramisu'),
onPressed: () {
Navigator.pop(context, 'Tiramisu');
},
),
new CupertinoDialogAction(
child: const Text('Apple Pie'),
onPressed: () {
Navigator.pop(context, 'Apple Pie');
},
),
new CupertinoDialogAction(
child: const Text("Devil's food cake"),
onPressed: () {
Navigator.pop(context, "Devil's food cake");
},
),
new CupertinoDialogAction(
child: const Text('Banana Split'),
onPressed: () {
Navigator.pop(context, 'Banana Split');
},
),
new CupertinoDialogAction(
child: const Text('Oatmeal Cookie'),
onPressed: () {
Navigator.pop(context, 'Oatmeal Cookies');
},
),
new CupertinoDialogAction(
child: const Text('Chocolate Brownie'),
onPressed: () {
Navigator.pop(context, 'Chocolate Brownies');
},
),
new CupertinoDialogAction(
child: const Text('Cancel'),
isDestructiveAction: true,
onPressed: () {
Navigator.pop(context, 'Cancel');
},
),
],
);
}
}
...@@ -148,20 +148,189 @@ void main() { ...@@ -148,20 +148,189 @@ void main() {
expect(scrollController.offset, 0.0); expect(scrollController.offset, 0.0);
scrollController.jumpTo(100.0); scrollController.jumpTo(100.0);
expect(scrollController.offset, 100.0); expect(scrollController.offset, 100.0);
// Set the scroll position back to zero.
scrollController.jumpTo(0.0);
// Find the actual dialog box. The first decorated box is the popup barrier. // Find the actual dialog box. The first decorated box is the popup barrier.
expect(tester.getSize(find.byType(DecoratedBox).at(1)), equals(const Size(270.0, 560.0))); expect(tester.getSize(find.byType(DecoratedBox).at(1)), equals(const Size(270.0, 560.0)));
// Check sizes/locations of the text. // Check sizes/locations of the text.
expect(tester.getSize(find.text('The Title')), equals(const Size(230.0, 171.0))); expect(tester.getSize(find.text('The Title')), equals(const Size(230.0, 171.0)));
expect(tester.getSize(find.text('Cancel')), equals(const Size(75.0, 300.0))); expect(tester.getSize(find.text('Cancel')), equals(const Size(87.0, 300.0)));
expect(tester.getSize(find.text('OK')), equals(const Size(75.0, 100.0))); expect(tester.getSize(find.text('OK')), equals(const Size(87.0, 100.0)));
expect(tester.getTopLeft(find.text('The Title')), equals(const Offset(285.0, 40.0))); expect(tester.getTopLeft(find.text('The Title')), equals(const Offset(285.0, 40.0)));
// The Cancel and OK buttons have different Y values because "Cancel" is // The Cancel and OK buttons have different Y values because "Cancel" is
// wrapping (as it should with large text sizes like this). // wrapping (as it should with large text sizes like this).
expect(tester.getTopLeft(find.text('Cancel')), equals(const Offset(295.0, 250.0))); expect(tester.getTopLeft(find.text('Cancel')), equals(const Offset(289.0, 466.0)));
expect(tester.getTopLeft(find.text('OK')), equals(const Offset(430.0, 350.0))); expect(tester.getTopLeft(find.text('OK')), equals(const Offset(424.0, 566.0)));
});
testWidgets('Button list is scrollable, has correct position with large text sizes.',
(WidgetTester tester) async {
const double textScaleFactor = 3.0;
final ScrollController scrollController = new ScrollController(keepScrollOffset: true);
await tester.pumpWidget(
new MaterialApp(home: new Material(
child: new Center(
child: new Builder(builder: (BuildContext context) {
return new RaisedButton(
onPressed: () {
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return new MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
child: new CupertinoAlertDialog(
title: const Text('The title'),
content: const Text('The content.'),
actions: const <Widget>[
const CupertinoDialogAction(
child: const Text('One'),
),
const CupertinoDialogAction(
child: const Text('Two'),
),
const CupertinoDialogAction(
child: const Text('Three'),
),
const CupertinoDialogAction(
child: const Text('Chocolate Brownies'),
),
const CupertinoDialogAction(
isDestructiveAction: true,
child: const Text('Cancel'),
),
],
actionScrollController: scrollController,
),
);
},
);
},
child: const Text('Go'),
);
}),
),
)),
);
await tester.tap(find.text('Go'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
// Check that the action buttons list is scrollable.
expect(scrollController.offset, 0.0);
scrollController.jumpTo(100.0);
expect(scrollController.offset, 100.0);
scrollController.jumpTo(0.0);
// Check that the action buttons are aligned vertically.
expect(tester.getCenter(find.widgetWithText(CupertinoDialogAction, 'One')).dx, equals(400.0));
expect(tester.getCenter(find.widgetWithText(CupertinoDialogAction, 'Two')).dx, equals(400.0));
expect(tester.getCenter(find.widgetWithText(CupertinoDialogAction, 'Three')).dx, equals(400.0));
expect(tester.getCenter(find.widgetWithText(CupertinoDialogAction, 'Chocolate Brownies')).dx, equals(400.0));
expect(tester.getCenter(find.widgetWithText(CupertinoDialogAction, 'Cancel')).dx, equals(400.0));
// Check that the action buttons are the correct heights.
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'One')).height, equals(98.0));
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Two')).height, equals(98.0));
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Three')).height, equals(148.0));
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Chocolate Brownies')).height, equals(298.0));
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Cancel')).height, equals(148.0));
});
testWidgets('Title Section is empty, Button section is not empty.',
(WidgetTester tester) async {
const double textScaleFactor = 1.0;
final ScrollController scrollController = new ScrollController(keepScrollOffset: true);
await tester.pumpWidget(
new MaterialApp(home: new Material(
child: new Center(
child: new Builder(builder: (BuildContext context) {
return new RaisedButton(
onPressed: () {
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return new MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
child: new CupertinoAlertDialog(
actions: const <Widget>[
const CupertinoDialogAction(
child: const Text('One'),
),
const CupertinoDialogAction(
child: const Text('Two'),
),
],
actionScrollController: scrollController,
),
);
},
);
},
child: const Text('Go'),
);
}),
),
)),
);
await tester.tap(find.text('Go'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
// Check that the title/message section is not displayed
expect(scrollController.offset, 0.0);
expect(tester.getTopLeft(find.widgetWithText(CupertinoDialogAction, 'One')).dy, equals(283.5));
// Check that the button's vertical size is the same.
expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'One')).height,
equals(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Two')).height));
});
testWidgets('Button section is empty, Title section is not empty.',
(WidgetTester tester) async {
const double textScaleFactor = 1.0;
final ScrollController scrollController = new ScrollController(keepScrollOffset: true);
await tester.pumpWidget(
new MaterialApp(home: new Material(
child: new Center(
child: new Builder(builder: (BuildContext context) {
return new RaisedButton(
onPressed: () {
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return new MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
child: new CupertinoAlertDialog(
title: const Text('The title'),
content: const Text('The content.'),
scrollController: scrollController,
),
);
},
);
},
child: const Text('Go'),
);
}),
),
)),
);
await tester.tap(find.text('Go'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
// Check that there's no button action section.
expect(scrollController.offset, 0.0);
expect(find.widgetWithText(CupertinoDialogAction, 'One'), findsNothing);
}); });
} }
......
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