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.
This commit is contained in:
@@ -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,
|
||||
|
||||
16
packages/flutter/test/material/debug_test.dart
Normal file
16
packages/flutter/test/material/debug_test.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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));
|
||||
});
|
||||
}
|
||||
|
||||
47
packages/flutter/test/material/ink_well_test.dart
Normal file
47
packages/flutter/test/material/ink_well_test.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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']));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user