Commit 28a214ba authored by Bernardo Ferrari's avatar Bernardo Ferrari Committed by Shi-Hao Hong

Add onLongPress to Buttons (#40641)

* Add onLongPress to Buttons.

* Button enabled status will now respond to onLongPress
parent dc44c566
...@@ -38,6 +38,7 @@ class RawMaterialButton extends StatefulWidget { ...@@ -38,6 +38,7 @@ class RawMaterialButton extends StatefulWidget {
const RawMaterialButton({ const RawMaterialButton({
Key key, Key key,
@required this.onPressed, @required this.onPressed,
this.onLongPress,
this.onHighlightChanged, this.onHighlightChanged,
this.textStyle, this.textStyle,
this.fillColor, this.fillColor,
...@@ -75,9 +76,22 @@ class RawMaterialButton extends StatefulWidget { ...@@ -75,9 +76,22 @@ class RawMaterialButton extends StatefulWidget {
/// Called when the button is tapped or otherwise activated. /// Called when the button is tapped or otherwise activated.
/// ///
/// If this is set to null, the button will be disabled, see [enabled]. /// If this callback and [onLongPress] are null, then the button will be disabled.
///
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback onPressed; final VoidCallback onPressed;
/// Called when the button is long-pressed.
///
/// If this callback and [onPressed] are null, then the button will be disabled.
///
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback onLongPress;
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged] /// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
/// callback. /// callback.
/// ///
...@@ -222,8 +236,8 @@ class RawMaterialButton extends StatefulWidget { ...@@ -222,8 +236,8 @@ class RawMaterialButton extends StatefulWidget {
/// Whether the button is enabled or disabled. /// Whether the button is enabled or disabled.
/// ///
/// Buttons are disabled by default. To enable a button, set its [onPressed] /// Buttons are disabled by default. To enable a button, set its [onPressed]
/// property to a non-null value. /// or [onLongPress] properties to a non-null value.
bool get enabled => onPressed != null; bool get enabled => onPressed != null || onLongPress != null;
/// Configures the minimum size of the tap target. /// Configures the minimum size of the tap target.
/// ///
...@@ -352,6 +366,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> { ...@@ -352,6 +366,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
hoverColor: widget.hoverColor, hoverColor: widget.hoverColor,
onHover: _handleHoveredChanged, onHover: _handleHoveredChanged,
onTap: widget.onPressed, onTap: widget.onPressed,
onLongPress: widget.onLongPress,
customBorder: effectiveShape, customBorder: effectiveShape,
child: IconTheme.merge( child: IconTheme.merge(
data: IconThemeData(color: effectiveTextColor), data: IconThemeData(color: effectiveTextColor),
......
...@@ -29,7 +29,7 @@ import 'theme_data.dart'; ...@@ -29,7 +29,7 @@ import 'theme_data.dart';
/// interactive, with ink splashes, without also committing to these stylistic /// interactive, with ink splashes, without also committing to these stylistic
/// choices, consider using [InkWell] instead. /// choices, consider using [InkWell] instead.
/// ///
/// If the [onPressed] callback is null, then the button will be disabled, /// If the [onPressed] and [onLongPress] callbacks are null, then this button will be disabled,
/// will not react to touch, and will be colored as specified by /// will not react to touch, and will be colored as specified by
/// the [disabledColor] property instead of the [color] property. If you are /// the [disabledColor] property instead of the [color] property. If you are
/// trying to change the button's [color] and it is not having any effect, check /// trying to change the button's [color] and it is not having any effect, check
...@@ -102,6 +102,7 @@ class FlatButton extends MaterialButton { ...@@ -102,6 +102,7 @@ class FlatButton extends MaterialButton {
const FlatButton({ const FlatButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -125,6 +126,7 @@ class FlatButton extends MaterialButton { ...@@ -125,6 +126,7 @@ class FlatButton extends MaterialButton {
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
...@@ -155,6 +157,7 @@ class FlatButton extends MaterialButton { ...@@ -155,6 +157,7 @@ class FlatButton extends MaterialButton {
factory FlatButton.icon({ factory FlatButton.icon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -182,6 +185,7 @@ class FlatButton extends MaterialButton { ...@@ -182,6 +185,7 @@ class FlatButton extends MaterialButton {
final ButtonThemeData buttonTheme = ButtonTheme.of(context); final ButtonThemeData buttonTheme = ButtonTheme.of(context);
return RawMaterialButton( return RawMaterialButton(
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
fillColor: buttonTheme.getFillColor(this), fillColor: buttonTheme.getFillColor(this),
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)), textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
...@@ -215,6 +219,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin { ...@@ -215,6 +219,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
_FlatButtonWithIcon({ _FlatButtonWithIcon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -241,6 +246,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin { ...@@ -241,6 +246,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
......
...@@ -21,8 +21,8 @@ import 'theme_data.dart'; ...@@ -21,8 +21,8 @@ import 'theme_data.dart';
/// ///
/// The button's size will expand to fit the child widget, if necessary. /// The button's size will expand to fit the child widget, if necessary.
/// ///
/// MaterialButtons whose [onPressed] handler is null will be disabled. To have /// MaterialButtons whose [onPressed] and [onLongPress] callbacks are null will be disabled. To have
/// an enabled button, make sure to pass a non-null value for onPressed. /// an enabled button, make sure to pass a non-null value for [onPressed] or [onLongPress].
/// ///
/// Rather than using this class directly, consider using [FlatButton], /// Rather than using this class directly, consider using [FlatButton],
/// [OutlineButton], or [RaisedButton], which configure this class with /// [OutlineButton], or [RaisedButton], which configure this class with
...@@ -51,6 +51,7 @@ class MaterialButton extends StatelessWidget { ...@@ -51,6 +51,7 @@ class MaterialButton extends StatelessWidget {
const MaterialButton({ const MaterialButton({
Key key, Key key,
@required this.onPressed, @required this.onPressed,
this.onLongPress,
this.onHighlightChanged, this.onHighlightChanged,
this.textTheme, this.textTheme,
this.textColor, this.textColor,
...@@ -88,9 +89,22 @@ class MaterialButton extends StatelessWidget { ...@@ -88,9 +89,22 @@ class MaterialButton extends StatelessWidget {
/// The callback that is called when the button is tapped or otherwise activated. /// The callback that is called when the button is tapped or otherwise activated.
/// ///
/// If this is set to null, the button will be disabled. /// If this callback and [onLongPress] are null, then the button will be disabled.
///
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback onPressed; final VoidCallback onPressed;
/// The callback that is called when the button is long-pressed.
///
/// If this callback and [onPressed] are null, then the button will be disabled.
///
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback onLongPress;
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged] /// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
/// callback. /// callback.
/// ///
...@@ -287,8 +301,8 @@ class MaterialButton extends StatelessWidget { ...@@ -287,8 +301,8 @@ class MaterialButton extends StatelessWidget {
/// Whether the button is enabled or disabled. /// Whether the button is enabled or disabled.
/// ///
/// Buttons are disabled by default. To enable a button, set its [onPressed] /// Buttons are disabled by default. To enable a button, set its [onPressed]
/// property to a non-null value. /// or [onLongPress] properties to a non-null value.
bool get enabled => onPressed != null; bool get enabled => onPressed != null || onLongPress != null;
/// The internal padding for the button's [child]. /// The internal padding for the button's [child].
/// ///
...@@ -348,6 +362,7 @@ class MaterialButton extends StatelessWidget { ...@@ -348,6 +362,7 @@ class MaterialButton extends StatelessWidget {
return RawMaterialButton( return RawMaterialButton(
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
fillColor: buttonTheme.getFillColor(this), fillColor: buttonTheme.getFillColor(this),
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)), textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
...@@ -377,7 +392,7 @@ class MaterialButton extends StatelessWidget { ...@@ -377,7 +392,7 @@ class MaterialButton extends StatelessWidget {
@override @override
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(ObjectFlagProperty<VoidCallback>('onPressed', onPressed, ifNull: 'disabled')); properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
properties.add(DiagnosticsProperty<ButtonTextTheme>('textTheme', textTheme, defaultValue: null)); properties.add(DiagnosticsProperty<ButtonTextTheme>('textTheme', textTheme, defaultValue: null));
properties.add(ColorProperty('textColor', textColor, defaultValue: null)); properties.add(ColorProperty('textColor', textColor, defaultValue: null));
properties.add(ColorProperty('disabledTextColor', disabledTextColor, defaultValue: null)); properties.add(ColorProperty('disabledTextColor', disabledTextColor, defaultValue: null));
......
...@@ -28,7 +28,7 @@ const Duration _kElevationDuration = Duration(milliseconds: 75); ...@@ -28,7 +28,7 @@ const Duration _kElevationDuration = Duration(milliseconds: 75);
/// wide grey rounded rectangle that does not change when the button is /// wide grey rounded rectangle that does not change when the button is
/// pressed or disabled. By default the button's background is transparent. /// pressed or disabled. By default the button's background is transparent.
/// ///
/// If the [onPressed] callback is null, then the button will be disabled and by /// If the [onPressed] or [onLongPress] callbacks are null, then the button will be disabled and by
/// default will resemble a flat button in the [disabledColor]. /// default will resemble a flat button in the [disabledColor].
/// ///
/// The button's [highlightElevation], which defines the size of the /// The button's [highlightElevation], which defines the size of the
...@@ -61,6 +61,7 @@ class OutlineButton extends MaterialButton { ...@@ -61,6 +61,7 @@ class OutlineButton extends MaterialButton {
const OutlineButton({ const OutlineButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
Color disabledTextColor, Color disabledTextColor,
...@@ -85,6 +86,7 @@ class OutlineButton extends MaterialButton { ...@@ -85,6 +86,7 @@ class OutlineButton extends MaterialButton {
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
disabledTextColor: disabledTextColor, disabledTextColor: disabledTextColor,
...@@ -113,6 +115,7 @@ class OutlineButton extends MaterialButton { ...@@ -113,6 +115,7 @@ class OutlineButton extends MaterialButton {
factory OutlineButton.icon({ factory OutlineButton.icon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
Color disabledTextColor, Color disabledTextColor,
...@@ -169,6 +172,7 @@ class OutlineButton extends MaterialButton { ...@@ -169,6 +172,7 @@ class OutlineButton extends MaterialButton {
final ButtonThemeData buttonTheme = ButtonTheme.of(context); final ButtonThemeData buttonTheme = ButtonTheme.of(context);
return _OutlineButton( return _OutlineButton(
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
brightness: buttonTheme.getBrightness(this), brightness: buttonTheme.getBrightness(this),
textTheme: textTheme, textTheme: textTheme,
textColor: buttonTheme.getTextColor(this), textColor: buttonTheme.getTextColor(this),
...@@ -207,6 +211,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi ...@@ -207,6 +211,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi
_OutlineButtonWithIcon({ _OutlineButtonWithIcon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
Color disabledTextColor, Color disabledTextColor,
...@@ -234,6 +239,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi ...@@ -234,6 +239,7 @@ class _OutlineButtonWithIcon extends OutlineButton with MaterialButtonWithIconMi
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
disabledTextColor: disabledTextColor, disabledTextColor: disabledTextColor,
...@@ -266,6 +272,7 @@ class _OutlineButton extends StatefulWidget { ...@@ -266,6 +272,7 @@ class _OutlineButton extends StatefulWidget {
const _OutlineButton({ const _OutlineButton({
Key key, Key key,
@required this.onPressed, @required this.onPressed,
this.onLongPress,
this.brightness, this.brightness,
this.textTheme, this.textTheme,
this.textColor, this.textColor,
...@@ -292,6 +299,7 @@ class _OutlineButton extends StatefulWidget { ...@@ -292,6 +299,7 @@ class _OutlineButton extends StatefulWidget {
super(key: key); super(key: key);
final VoidCallback onPressed; final VoidCallback onPressed;
final VoidCallback onLongPress;
final Brightness brightness; final Brightness brightness;
final ButtonTextTheme textTheme; final ButtonTextTheme textTheme;
final Color textColor; final Color textColor;
...@@ -312,7 +320,7 @@ class _OutlineButton extends StatefulWidget { ...@@ -312,7 +320,7 @@ class _OutlineButton extends StatefulWidget {
final bool autofocus; final bool autofocus;
final Widget child; final Widget child;
bool get enabled => onPressed != null; bool get enabled => onPressed != null || onLongPress != null;
@override @override
_OutlineButtonState createState() => _OutlineButtonState(); _OutlineButtonState createState() => _OutlineButtonState();
...@@ -440,6 +448,7 @@ class _OutlineButtonState extends State<_OutlineButton> with SingleTickerProvide ...@@ -440,6 +448,7 @@ class _OutlineButtonState extends State<_OutlineButton> with SingleTickerProvide
highlightColor: widget.highlightColor, highlightColor: widget.highlightColor,
disabledColor: Colors.transparent, disabledColor: Colors.transparent,
onPressed: widget.onPressed, onPressed: widget.onPressed,
onLongPress: widget.onLongPress,
elevation: 0.0, elevation: 0.0,
disabledElevation: 0.0, disabledElevation: 0.0,
focusElevation: 0.0, focusElevation: 0.0,
......
...@@ -20,10 +20,10 @@ import 'theme_data.dart'; ...@@ -20,10 +20,10 @@ import 'theme_data.dart';
/// in long busy lists of content, or in wide spaces. Avoid using raised buttons /// in long busy lists of content, or in wide spaces. Avoid using raised buttons
/// on already-raised content such as dialogs or cards. /// on already-raised content such as dialogs or cards.
/// ///
/// If the [onPressed] callback is null, then the button will be disabled and by /// If [onPressed] and [onLongPress] callbacks are null, then the button will be disabled and by
/// default will resemble a flat button in the [disabledColor]. If you are /// default will resemble a flat button in the [disabledColor]. If you are
/// trying to change the button's [color] and it is not having any effect, check /// trying to change the button's [color] and it is not having any effect, check
/// that you are passing a non-null [onPressed] handler. /// that you are passing a non-null [onPressed] or [onLongPress] callbacks.
/// ///
/// If you want an ink-splash effect for taps, but don't want to use a button, /// If you want an ink-splash effect for taps, but don't want to use a button,
/// consider using [InkWell] directly. /// consider using [InkWell] directly.
...@@ -108,6 +108,7 @@ class RaisedButton extends MaterialButton { ...@@ -108,6 +108,7 @@ class RaisedButton extends MaterialButton {
const RaisedButton({ const RaisedButton({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -142,6 +143,7 @@ class RaisedButton extends MaterialButton { ...@@ -142,6 +143,7 @@ class RaisedButton extends MaterialButton {
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
...@@ -179,6 +181,7 @@ class RaisedButton extends MaterialButton { ...@@ -179,6 +181,7 @@ class RaisedButton extends MaterialButton {
factory RaisedButton.icon({ factory RaisedButton.icon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -209,6 +212,7 @@ class RaisedButton extends MaterialButton { ...@@ -209,6 +212,7 @@ class RaisedButton extends MaterialButton {
final ButtonThemeData buttonTheme = ButtonTheme.of(context); final ButtonThemeData buttonTheme = ButtonTheme.of(context);
return RawMaterialButton( return RawMaterialButton(
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
fillColor: buttonTheme.getFillColor(this), fillColor: buttonTheme.getFillColor(this),
...@@ -252,6 +256,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi ...@@ -252,6 +256,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi
_RaisedButtonWithIcon({ _RaisedButtonWithIcon({
Key key, Key key,
@required VoidCallback onPressed, @required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged, ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme, ButtonTextTheme textTheme,
Color textColor, Color textColor,
...@@ -284,6 +289,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi ...@@ -284,6 +289,7 @@ class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixi
super( super(
key: key, key: key,
onPressed: onPressed, onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged, onHighlightChanged: onHighlightChanged,
textTheme: textTheme, textTheme: textTheme,
textColor: textColor, textColor: textColor,
......
...@@ -333,6 +333,81 @@ void main() { ...@@ -333,6 +333,81 @@ void main() {
paintsExactlyCountTimes(#clipPath, 0), paintsExactlyCountTimes(#clipPath, 0),
); );
}); });
testWidgets('FlatButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
bool wasPressed;
Finder flatButton;
Widget buildFrame({ VoidCallback onPressed, VoidCallback onLongPress }) {
return Directionality(
textDirection: TextDirection.ltr,
child: FlatButton(
child: const Text('button'),
onPressed: onPressed,
onLongPress: onLongPress,
),
);
}
// onPressed not null, onLongPress null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: () { wasPressed = true; }, onLongPress: null),
);
flatButton = find.byType(FlatButton);
expect(tester.widget<FlatButton>(flatButton).enabled, true);
await tester.tap(flatButton);
expect(wasPressed, true);
// onPressed null, onLongPress not null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: () { wasPressed = true; }),
);
flatButton = find.byType(FlatButton);
expect(tester.widget<FlatButton>(flatButton).enabled, true);
await tester.longPress(flatButton);
expect(wasPressed, true);
// onPressed null, onLongPress null.
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: null),
);
flatButton = find.byType(FlatButton);
expect(tester.widget<FlatButton>(flatButton).enabled, false);
});
testWidgets('FlatButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
bool didPressButton = false;
bool didLongPressButton = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: FlatButton(
onPressed: () {
didPressButton = true;
},
onLongPress: () {
didLongPressButton = true;
},
child: const Text('button'),
),
),
);
final Finder flatButton = find.byType(FlatButton);
expect(tester.widget<FlatButton>(flatButton).enabled, true);
expect(didPressButton, isFalse);
await tester.tap(flatButton);
expect(didPressButton, isTrue);
expect(didLongPressButton, isFalse);
await tester.longPress(flatButton);
expect(didLongPressButton, isTrue);
});
} }
TextStyle _iconStyle(WidgetTester tester, IconData icon) { TextStyle _iconStyle(WidgetTester tester, IconData icon) {
......
...@@ -298,6 +298,81 @@ void main() { ...@@ -298,6 +298,81 @@ void main() {
expect(focusNode.hasPrimaryFocus, isTrue); expect(focusNode.hasPrimaryFocus, isTrue);
}); });
testWidgets('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
bool wasPressed;
Finder materialButton;
Widget buildFrame({ VoidCallback onPressed, VoidCallback onLongPress }) {
return Directionality(
textDirection: TextDirection.ltr,
child: MaterialButton(
child: const Text('button'),
onPressed: onPressed,
onLongPress: onLongPress,
),
);
}
// onPressed not null, onLongPress null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: () { wasPressed = true; }, onLongPress: null),
);
materialButton = find.byType(MaterialButton);
expect(tester.widget<MaterialButton>(materialButton).enabled, true);
await tester.tap(materialButton);
expect(wasPressed, true);
// onPressed null, onLongPress not null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: () { wasPressed = true; }),
);
materialButton = find.byType(MaterialButton);
expect(tester.widget<MaterialButton>(materialButton).enabled, true);
await tester.longPress(materialButton);
expect(wasPressed, true);
// onPressed null, onLongPress null.
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: null),
);
materialButton = find.byType(MaterialButton);
expect(tester.widget<MaterialButton>(materialButton).enabled, false);
});
testWidgets('MaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
bool didPressButton = false;
bool didLongPressButton = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: MaterialButton(
onPressed: () {
didPressButton = true;
},
onLongPress: () {
didLongPressButton = true;
},
child: const Text('button'),
),
),
);
final Finder materialButton = find.byType(MaterialButton);
expect(tester.widget<MaterialButton>(materialButton).enabled, true);
expect(didPressButton, isFalse);
await tester.tap(materialButton);
expect(didPressButton, isTrue);
expect(didLongPressButton, isFalse);
await tester.longPress(materialButton);
expect(didLongPressButton, isTrue);
});
// This test is very similar to the '...explicit splashColor and highlightColor' test // This test is very similar to the '...explicit splashColor and highlightColor' test
// in icon_button_test.dart. If you change this one, you may want to also change that one. // in icon_button_test.dart. If you change this one, you may want to also change that one.
testWidgets('MaterialButton with explicit splashColor and highlightColor', (WidgetTester tester) async { testWidgets('MaterialButton with explicit splashColor and highlightColor', (WidgetTester tester) async {
......
...@@ -450,37 +450,48 @@ void main() { ...@@ -450,37 +450,48 @@ void main() {
expect(find.byType(OutlineButton), paints..path(color: disabledColor)); expect(find.byType(OutlineButton), paints..path(color: disabledColor));
}); });
testWidgets('Outline button responds to tap when enabled', (WidgetTester tester) async { testWidgets('OutlineButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
int pressedCount = 0;
Widget buildFrame(VoidCallback onPressed) { bool wasPressed;
Finder outlineButton;
Widget buildFrame({ VoidCallback onPressed, VoidCallback onLongPress }) {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: Theme( child: OutlineButton(
data: ThemeData(), child: const Text('button'),
child: Center( onPressed: onPressed,
child: OutlineButton(onPressed: onPressed), onLongPress: onLongPress,
),
), ),
); );
} }
// onPressed not null, onLongPress null.
wasPressed = false;
await tester.pumpWidget( await tester.pumpWidget(
buildFrame(() { pressedCount += 1; }), buildFrame(onPressed: () { wasPressed = true; }, onLongPress: null),
); );
expect(tester.widget<OutlineButton>(find.byType(OutlineButton)).enabled, true); outlineButton = find.byType(OutlineButton);
await tester.tap(find.byType(OutlineButton)); expect(tester.widget<OutlineButton>(outlineButton).enabled, true);
await tester.pumpAndSettle(); await tester.tap(outlineButton);
expect(pressedCount, 1); expect(wasPressed, true);
// onPressed null, onLongPress not null.
wasPressed = false;
await tester.pumpWidget( await tester.pumpWidget(
buildFrame(null), buildFrame(onPressed: null, onLongPress: () { wasPressed = true; }),
); );
final Finder outlineButton = find.byType(OutlineButton); outlineButton = find.byType(OutlineButton);
expect(tester.widget<OutlineButton>(outlineButton).enabled, true);
await tester.longPress(outlineButton);
expect(wasPressed, true);
// onPressed null, onLongPress null.
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: null),
);
outlineButton = find.byType(OutlineButton);
expect(tester.widget<OutlineButton>(outlineButton).enabled, false); expect(tester.widget<OutlineButton>(outlineButton).enabled, false);
await tester.tap(outlineButton);
await tester.pumpAndSettle();
expect(pressedCount, 1);
}); });
testWidgets('Outline button doesn\'t crash if disabled during a gesture', (WidgetTester tester) async { testWidgets('Outline button doesn\'t crash if disabled during a gesture', (WidgetTester tester) async {
...@@ -814,6 +825,37 @@ void main() { ...@@ -814,6 +825,37 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
_checkPhysicalLayer(buttonElement, fillColor.withAlpha(0x00)); _checkPhysicalLayer(buttonElement, fillColor.withAlpha(0x00));
}); });
testWidgets('OutlineButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
bool didPressButton = false;
bool didLongPressButton = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: OutlineButton(
onPressed: () {
didPressButton = true;
},
onLongPress: () {
didLongPressButton = true;
},
child: const Text('button'),
),
),
);
final Finder outlineButton = find.byType(OutlineButton);
expect(tester.widget<OutlineButton>(outlineButton).enabled, true);
expect(didPressButton, isFalse);
await tester.tap(outlineButton);
expect(didPressButton, isTrue);
expect(didLongPressButton, isFalse);
await tester.longPress(outlineButton);
expect(didLongPressButton, isTrue);
});
} }
PhysicalModelLayer _findPhysicalLayer(Element element) { PhysicalModelLayer _findPhysicalLayer(Element element) {
......
...@@ -250,6 +250,81 @@ void main() { ...@@ -250,6 +250,81 @@ void main() {
expect(textColor(), equals(disabledColor)); expect(textColor(), equals(disabledColor));
expect(textColor(), isNot(unusedDisabledTextColor)); expect(textColor(), isNot(unusedDisabledTextColor));
}); });
testWidgets('RaisedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
bool wasPressed;
Finder raisedButton;
Widget buildFrame({ VoidCallback onPressed, VoidCallback onLongPress }) {
return Directionality(
textDirection: TextDirection.ltr,
child: RaisedButton(
child: const Text('button'),
onPressed: onPressed,
onLongPress: onLongPress,
),
);
}
// onPressed not null, onLongPress null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: () { wasPressed = true; }, onLongPress: null),
);
raisedButton = find.byType(RaisedButton);
expect(tester.widget<RaisedButton>(raisedButton).enabled, true);
await tester.tap(raisedButton);
expect(wasPressed, true);
// onPressed null, onLongPress not null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: () { wasPressed = true; }),
);
raisedButton = find.byType(RaisedButton);
expect(tester.widget<RaisedButton>(raisedButton).enabled, true);
await tester.longPress(raisedButton);
expect(wasPressed, true);
// onPressed null, onLongPress null.
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: null),
);
raisedButton = find.byType(RaisedButton);
expect(tester.widget<RaisedButton>(raisedButton).enabled, false);
});
testWidgets('RaisedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
bool didPressButton = false;
bool didLongPressButton = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: RaisedButton(
onPressed: () {
didPressButton = true;
},
onLongPress: () {
didLongPressButton = true;
},
child: const Text('button'),
),
),
);
final Finder raisedButton = find.byType(RaisedButton);
expect(tester.widget<RaisedButton>(raisedButton).enabled, true);
expect(didPressButton, isFalse);
await tester.tap(raisedButton);
expect(didPressButton, isTrue);
expect(didLongPressButton, isFalse);
await tester.longPress(raisedButton);
expect(didLongPressButton, isTrue);
});
} }
TextStyle _iconStyle(WidgetTester tester, IconData icon) { TextStyle _iconStyle(WidgetTester tester, IconData icon) {
......
...@@ -435,4 +435,79 @@ void main() { ...@@ -435,4 +435,79 @@ void main() {
expect(box, paints..rect(color: hoverColor)); expect(box, paints..rect(color: hoverColor));
}); });
testWidgets('RawMaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
bool wasPressed;
Finder rawMaterialButton;
Widget buildFrame({ VoidCallback onPressed, VoidCallback onLongPress }) {
return Directionality(
textDirection: TextDirection.ltr,
child: RawMaterialButton(
child: const Text('button'),
onPressed: onPressed,
onLongPress: onLongPress,
),
);
}
// onPressed not null, onLongPress null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: () { wasPressed = true; }, onLongPress: null),
);
rawMaterialButton = find.byType(RawMaterialButton);
expect(tester.widget<RawMaterialButton>(rawMaterialButton).enabled, true);
await tester.tap(rawMaterialButton);
expect(wasPressed, true);
// onPressed null, onLongPress not null.
wasPressed = false;
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: () { wasPressed = true; }),
);
rawMaterialButton = find.byType(RawMaterialButton);
expect(tester.widget<RawMaterialButton>(rawMaterialButton).enabled, true);
await tester.longPress(rawMaterialButton);
expect(wasPressed, true);
// onPressed null, onLongPress null.
await tester.pumpWidget(
buildFrame(onPressed: null, onLongPress: null),
);
rawMaterialButton = find.byType(RawMaterialButton);
expect(tester.widget<RawMaterialButton>(rawMaterialButton).enabled, false);
});
testWidgets('RawMaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
bool didPressButton = false;
bool didLongPressButton = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: RawMaterialButton(
onPressed: () {
didPressButton = true;
},
onLongPress: () {
didLongPressButton = true;
},
child: const Text('button'),
),
),
);
final Finder rawMaterialButton = find.byType(RawMaterialButton);
expect(tester.widget<RawMaterialButton>(rawMaterialButton).enabled, true);
expect(didPressButton, isFalse);
await tester.tap(rawMaterialButton);
expect(didPressButton, isTrue);
expect(didLongPressButton, isFalse);
await tester.longPress(rawMaterialButton);
expect(didLongPressButton, isTrue);
});
} }
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