Commit ad27fcd3 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add SimpleDialogOption (#7494)

The demo of the SimpleDialog had some useful code that should really be part of
the framework. This patch extracts it into a SimpleDialogOption widget.

Remove debugCheckHasScaffold because it is unused.

Also, add tests for InkWell, SimpleDialog, and other widgets.
parent 3b702448
......@@ -29,22 +29,19 @@ class DialogDemoItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: onPressed,
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Icon(icon, size: 36.0, color: color),
new Padding(
padding: const EdgeInsets.only(left: 16.0),
child: new Text(text)
)
]
)
)
return new SimpleDialogOption(
onPressed: onPressed,
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Icon(icon, size: 36.0, color: color),
new Padding(
padding: const EdgeInsets.only(left: 16.0),
child: new Text(text),
),
],
),
);
}
}
......
......@@ -5,7 +5,6 @@
import 'package:flutter/widgets.dart';
import 'material.dart';
import 'scaffold.dart';
/// Asserts that the given context has a [Material] ancestor.
///
......@@ -42,37 +41,3 @@ bool debugCheckHasMaterial(BuildContext context) {
});
return true;
}
/// Asserts that the given context has a [Scaffold] ancestor.
///
/// Used by some material design widgets to make sure that they are
/// only used in contexts where they can communicate with a Scaffold.
///
/// For example, the [AppBar] in some situations requires a Scaffold
/// to do the right thing with scrolling.
///
/// To call this function, use the following pattern, typically in the
/// relevant Widget's [build] method:
///
/// ```dart
/// assert(debugCheckHasScaffold(context));
/// ```
///
/// Does nothing if asserts are disabled. Always returns true.
bool debugCheckHasScaffold(BuildContext context) {
assert(() {
if (Scaffold.of(context) == null) {
Element element = context;
throw new FlutterError(
'No Scaffold widget found.\n'
'${context.widget.runtimeType} widgets require a Scaffold widget ancestor.\n'
'The specific widget that could not find a Scaffold ancestor was:\n'
' ${context.widget}\n'
'The ownership chain for the affected widget is:\n'
' ${element.debugGetCreatorChain(10)}'
);
}
return true;
});
return true;
}
......@@ -10,6 +10,7 @@ import 'package:meta/meta.dart';
import 'button.dart';
import 'button_bar.dart';
import 'colors.dart';
import 'ink_well.dart';
import 'material.dart';
import 'theme.dart';
......@@ -176,6 +177,50 @@ class AlertDialog extends StatelessWidget {
}
}
/// An option used in a [SimpleDialog].
///
/// A simple dialog offers the user a choice between several options. This
/// widget is commonly used to represent each of the options. If the user
/// selects this option, the widget will call the [onPressed] callback, which
/// typically uses [Navigator.pop] to close the dialog.
///
/// See also:
///
/// * [SimpleDialog], for a dialog in which to use this widget.
/// * [showDialog], which actually displays the dialog and returns its result.
/// * [FlatButton], which are commonly used as actions in other kinds of
/// dialogs, such as [AlertDialog]s.
/// * <https://material.google.com/components/dialogs.html#dialogs-simple-dialogs>
class SimpleDialogOption extends StatelessWidget {
/// Creates an option for a [SimpleDialog].
SimpleDialogOption({
Key key,
this.onPressed,
this.child,
}) : super(key: key);
/// The callback that is called when this option is selected.
///
/// If this is set to null, the option cannot be selected.
final VoidCallback onPressed;
/// The widget below this widget in the tree.
///
/// Typically a [Text] widget.
final Widget child;
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: onPressed,
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
child: child
),
);
}
}
/// A simple material design dialog.
///
/// A simple dialog offers the user a choice between several options. A simple
......@@ -189,6 +234,7 @@ class AlertDialog extends StatelessWidget {
///
/// See also:
///
/// * [SimpleDialogOption], which are options used in this type of dialog.
/// * [AlertDialog], for dialogs that have a row of buttons below the body.
/// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based.
/// * [showDialog], which actually displays the dialog and returns its result.
......@@ -220,8 +266,7 @@ class SimpleDialog extends StatelessWidget {
/// The (optional) content of the dialog is displayed in a [Block] underneath
/// the title.
///
/// The children are assumed to have 8.0 pixels of vertical and 24.0 pixels of
/// horizontal padding internally.
/// Typically a list of [SimpleDialogOption]s.
final List<Widget> children;
/// Padding around the content.
......
......@@ -31,8 +31,10 @@ import 'theme.dart';
///
/// See also:
///
/// * [RaisedButton]
/// * [DropdownButton]
/// * [RaisedButton], which is a button that hovers above the containing
/// material.
/// * [DropdownButton], which offers the user a choice of a number of options.
/// * [SimpleDialogOption], which is used in [SimpleDialog]s.
/// * <https://material.google.com/components/buttons.html>
class FlatButton extends StatelessWidget {
/// Creates a flat button.
......
......@@ -114,13 +114,13 @@ class RaisedButton extends StatelessWidget {
if (disabledColor != null)
return disabledColor;
Brightness brightness = Theme.of(context).brightness;
assert(brightness != null);
switch (brightness) {
case Brightness.light:
return Colors.black12;
case Brightness.dark:
return Colors.white12;
}
assert(brightness != null);
return null;
}
}
......
......@@ -6,6 +6,37 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
void main() {
test('MaterialPointArcTween control test', () {
MaterialPointArcTween a = new MaterialPointArcTween(
begin: Point.origin,
end: const Point(0.0, 10.0)
);
MaterialPointArcTween b = new MaterialPointArcTween(
begin: Point.origin,
end: const Point(0.0, 10.0)
);
expect(a, hasOneLineDescription);
expect(a, equals(b));
expect(a.hashCode, equals(b.hashCode));
});
test('MaterialRectArcTween control test', () {
MaterialRectArcTween a = new MaterialRectArcTween(
begin: new Rect.fromLTWH(0.0, 0.0, 10.0, 10.0),
end: new Rect.fromLTWH(0.0, 10.0, 10.0, 10.0)
);
MaterialRectArcTween b = new MaterialRectArcTween(
begin: new Rect.fromLTWH(0.0, 0.0, 10.0, 10.0),
end: new Rect.fromLTWH(0.0, 10.0, 10.0, 10.0)
);
expect(a, hasOneLineDescription);
expect(a, equals(b));
expect(a.hashCode, equals(b.hashCode));
});
test('on-axis MaterialPointArcTween', () {
MaterialPointArcTween tween = new MaterialPointArcTween(
begin: Point.origin,
......
// Copyright 2016 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 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('debugCheckHasMaterial control test', (WidgetTester tester) async {
await tester.pumpWidget(new FlatButton(
onPressed: null,
child: new Text('Go'),
));
expect(tester.takeException(), isFlutterError);
});
}
......@@ -55,7 +55,7 @@ void main() {
await tester.tap(find.text('OK'));
expect(didPressOk, true);
});
testWidgets('Dialog background color', (WidgetTester tester) async {
await tester.pumpWidget(
......@@ -71,18 +71,18 @@ void main() {
showDialog(
context: context,
child: new AlertDialog(
title: new Text('Title'),
content: new Text('Y'),
actions: <Widget>[
]
)
actions: <Widget>[ ],
),
);
}
)
},
),
);
}
)
)
)
},
),
),
),
);
await tester.tap(find.text('X'));
......@@ -96,4 +96,49 @@ void main() {
expect(materialconfig.elevation, 24);
expect(materialconfig.color, Colors.grey[800]);
});
testWidgets('Simple dialog control test', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
home: new Material(
child: new Center(
child: new RaisedButton(
onPressed: null,
child: new Text('Go'),
),
),
),
),
);
BuildContext context = tester.element(find.text('Go'));
Future<int> result = showDialog(
context: context,
child: new SimpleDialog(
title: new Text('Title'),
children: <Widget>[
new SimpleDialogOption(
onPressed: () {
Navigator.pop(context, 42);
},
child: new Text('First option'),
),
new SimpleDialogOption(
child: new Text('Second option'),
),
],
),
);
await tester.pumpUntilNoTransientCallbacks(const Duration(seconds: 1));
expect(find.text('Title'), findsOneWidget);
await tester.tap(find.text('First option'));
expect(await result, equals(42));
// TODO(abarth): Remove once https://github.com/flutter/flutter/issues/7457
// is fixed.
await tester.pumpUntilNoTransientCallbacks(const Duration(seconds: 1));
});
}
// Copyright 2016 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 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('InkWell gestures control test', (WidgetTester tester) async {
List<String> log = <String>[];
await tester.pumpWidget(new Material(
child: new Center(
child: new InkWell(
onTap: () {
log.add('tap');
},
onDoubleTap: () {
log.add('double-tap');
},
onLongPress: () {
log.add('long-press');
},
),
),
));
await tester.tap(find.byType(InkWell), pointer: 1);
expect(log, isEmpty);
await tester.pump(const Duration(seconds: 1));
expect(log, equals(<String>['tap']));
log.clear();
await tester.tap(find.byType(InkWell), pointer: 2);
await tester.tap(find.byType(InkWell), pointer: 3);
expect(log, equals(<String>['double-tap']));
log.clear();
await tester.longPress(find.byType(InkWell), pointer: 4);
expect(log, equals(<String>['long-press']));
});
}
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