Unverified Commit d1187487 authored by Chinmoy's avatar Chinmoy Committed by GitHub

Added enableFeedback property to FloatingActionButton (#69826)

parent 02efffc1
...@@ -147,6 +147,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -147,6 +147,7 @@ class FloatingActionButton extends StatelessWidget {
this.autofocus = false, this.autofocus = false,
this.materialTapTargetSize, this.materialTapTargetSize,
this.isExtended = false, this.isExtended = false,
this.enableFeedback,
}) : assert(elevation == null || elevation >= 0.0), }) : assert(elevation == null || elevation >= 0.0),
assert(focusElevation == null || focusElevation >= 0.0), assert(focusElevation == null || focusElevation >= 0.0),
assert(hoverElevation == null || hoverElevation >= 0.0), assert(hoverElevation == null || hoverElevation >= 0.0),
...@@ -189,6 +190,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -189,6 +190,7 @@ class FloatingActionButton extends StatelessWidget {
this.autofocus = false, this.autofocus = false,
Widget? icon, Widget? icon,
required Widget label, required Widget label,
this.enableFeedback,
}) : assert(elevation == null || elevation >= 0.0), }) : assert(elevation == null || elevation >= 0.0),
assert(focusElevation == null || focusElevation >= 0.0), assert(focusElevation == null || focusElevation >= 0.0),
assert(hoverElevation == null || hoverElevation >= 0.0), assert(hoverElevation == null || hoverElevation >= 0.0),
...@@ -409,6 +411,19 @@ class FloatingActionButton extends StatelessWidget { ...@@ -409,6 +411,19 @@ class FloatingActionButton extends StatelessWidget {
/// * [MaterialTapTargetSize], for a description of how this affects tap targets. /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize? materialTapTargetSize; final MaterialTapTargetSize? materialTapTargetSize;
/// Whether detected gestures should provide acoustic and/or haptic feedback.
///
/// For example, on Android a tap will produce a clicking sound and a
/// long-press will produce a short vibration, when feedback is enabled.
///
/// If null, [FloatingActionButtonThemeData.enableFeedback] is used.
/// If both are null, then default value is true.
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
final BoxConstraints _sizeConstraints; final BoxConstraints _sizeConstraints;
static const double _defaultElevation = 6; static const double _defaultElevation = 6;
...@@ -455,6 +470,8 @@ class FloatingActionButton extends StatelessWidget { ...@@ -455,6 +470,8 @@ class FloatingActionButton extends StatelessWidget {
?? _defaultHighlightElevation; ?? _defaultHighlightElevation;
final MaterialTapTargetSize materialTapTargetSize = this.materialTapTargetSize final MaterialTapTargetSize materialTapTargetSize = this.materialTapTargetSize
?? theme.materialTapTargetSize; ?? theme.materialTapTargetSize;
final bool enableFeedback = this.enableFeedback
?? floatingActionButtonTheme.enableFeedback ?? true;
final TextStyle textStyle = theme.textTheme.button!.copyWith( final TextStyle textStyle = theme.textTheme.button!.copyWith(
color: foregroundColor, color: foregroundColor,
letterSpacing: 1.2, letterSpacing: 1.2,
...@@ -483,6 +500,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -483,6 +500,7 @@ class FloatingActionButton extends StatelessWidget {
focusNode: focusNode, focusNode: focusNode,
autofocus: autofocus, autofocus: autofocus,
child: child, child: child,
enableFeedback: enableFeedback,
); );
if (tooltip != null) { if (tooltip != null) {
......
...@@ -42,6 +42,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -42,6 +42,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
this.disabledElevation, this.disabledElevation,
this.highlightElevation, this.highlightElevation,
this.shape, this.shape,
this.enableFeedback,
}); });
/// Color to be used for the unselected, enabled [FloatingActionButton]'s /// Color to be used for the unselected, enabled [FloatingActionButton]'s
...@@ -89,6 +90,12 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -89,6 +90,12 @@ class FloatingActionButtonThemeData with Diagnosticable {
/// The shape to be used for the floating action button's [Material]. /// The shape to be used for the floating action button's [Material].
final ShapeBorder? shape; final ShapeBorder? shape;
/// If specified, defines the feedback property for [FloatingActionButton].
///
/// If [FloatingActionButton.enableFeedback] is provided, [enableFeedback] is
/// ignored.
final bool? enableFeedback;
/// Creates a copy of this object with the given fields replaced with the /// Creates a copy of this object with the given fields replaced with the
/// new values. /// new values.
FloatingActionButtonThemeData copyWith({ FloatingActionButtonThemeData copyWith({
...@@ -103,6 +110,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -103,6 +110,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
double? disabledElevation, double? disabledElevation,
double? highlightElevation, double? highlightElevation,
ShapeBorder? shape, ShapeBorder? shape,
bool? enableFeedback,
}) { }) {
return FloatingActionButtonThemeData( return FloatingActionButtonThemeData(
foregroundColor: foregroundColor ?? this.foregroundColor, foregroundColor: foregroundColor ?? this.foregroundColor,
...@@ -116,6 +124,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -116,6 +124,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
disabledElevation: disabledElevation ?? this.disabledElevation, disabledElevation: disabledElevation ?? this.disabledElevation,
highlightElevation: highlightElevation ?? this.highlightElevation, highlightElevation: highlightElevation ?? this.highlightElevation,
shape: shape ?? this.shape, shape: shape ?? this.shape,
enableFeedback: enableFeedback ?? this.enableFeedback,
); );
} }
...@@ -140,6 +149,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -140,6 +149,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
disabledElevation: lerpDouble(a?.disabledElevation, b?.disabledElevation, t), disabledElevation: lerpDouble(a?.disabledElevation, b?.disabledElevation, t),
highlightElevation: lerpDouble(a?.highlightElevation, b?.highlightElevation, t), highlightElevation: lerpDouble(a?.highlightElevation, b?.highlightElevation, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
); );
} }
...@@ -157,6 +167,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -157,6 +167,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
disabledElevation, disabledElevation,
highlightElevation, highlightElevation,
shape, shape,
enableFeedback,
); );
} }
...@@ -177,7 +188,8 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -177,7 +188,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
&& other.hoverElevation == hoverElevation && other.hoverElevation == hoverElevation
&& other.disabledElevation == disabledElevation && other.disabledElevation == disabledElevation
&& other.highlightElevation == highlightElevation && other.highlightElevation == highlightElevation
&& other.shape == shape; && other.shape == shape
&& other.enableFeedback == enableFeedback;
} }
@override @override
...@@ -196,5 +208,6 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -196,5 +208,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
properties.add(DoubleProperty('disabledElevation', disabledElevation, defaultValue: defaultData.disabledElevation)); properties.add(DoubleProperty('disabledElevation', disabledElevation, defaultValue: defaultData.disabledElevation));
properties.add(DoubleProperty('highlightElevation', highlightElevation, defaultValue: defaultData.highlightElevation)); properties.add(DoubleProperty('highlightElevation', highlightElevation, defaultValue: defaultData.highlightElevation));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultData.shape)); properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultData.shape));
properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: defaultData.enableFeedback));
} }
} }
...@@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
void main() { void main() {
testWidgets('Floating Action Button control test', (WidgetTester tester) async { testWidgets('Floating Action Button control test', (WidgetTester tester) async {
...@@ -963,6 +964,116 @@ void main() { ...@@ -963,6 +964,116 @@ void main() {
expect(find.byKey(iconKey), findsOneWidget); expect(find.byKey(iconKey), findsOneWidget);
expect(find.byKey(labelKey), findsNothing); expect(find.byKey(labelKey), findsNothing);
}); });
group('feedback', () {
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
});
tearDown(() {
feedback.dispose();
});
testWidgets('FloatingActionButton with enabled feedback', (WidgetTester tester) async {
const bool enableFeedback = true;
await tester.pumpWidget(MaterialApp(
home: FloatingActionButton(
onPressed: () {},
enableFeedback: enableFeedback,
child: const Icon(Icons.access_alarm),
),
));
await tester.tap(find.byType(RawMaterialButton));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
testWidgets('FloatingActionButton with disabled feedback', (WidgetTester tester) async {
const bool enableFeedback = false;
await tester.pumpWidget(MaterialApp(
home: FloatingActionButton(
onPressed: () {},
enableFeedback: enableFeedback,
child: const Icon(Icons.access_alarm),
),
));
await tester.tap(find.byType(RawMaterialButton));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
});
testWidgets('FloatingActionButton with enabled feedback by default', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.access_alarm),
),
));
await tester.tap(find.byType(RawMaterialButton));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
testWidgets('FloatingActionButton with disabled feedback using FloatingActionButtonTheme', (WidgetTester tester) async {
const bool enableFeedbackTheme = false;
final ThemeData theme = ThemeData(
floatingActionButtonTheme: const FloatingActionButtonThemeData(
enableFeedback: enableFeedbackTheme,
),
);
await tester.pumpWidget(MaterialApp(
home: Theme(
data: theme,
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.access_alarm),
),
),
));
await tester.tap(find.byType(RawMaterialButton));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
});
testWidgets('FloatingActionButton.enableFeedback is overriden by FloatingActionButtonThemeData.enableFeedback', (WidgetTester tester) async {
const bool enableFeedbackTheme = false;
const bool enableFeedback = true;
final ThemeData theme = ThemeData(
floatingActionButtonTheme: const FloatingActionButtonThemeData(
enableFeedback: enableFeedbackTheme,
),
);
await tester.pumpWidget(MaterialApp(
home: Theme(
data: theme,
child: FloatingActionButton(
enableFeedback: enableFeedback,
onPressed: () {},
child: const Icon(Icons.access_alarm),
),
),
));
await tester.tap(find.byType(RawMaterialButton));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
});
} }
Offset _rightEdgeOfFab(WidgetTester tester) { Offset _rightEdgeOfFab(WidgetTester tester) {
......
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