Unverified Commit 44d7bd35 authored by Chinmoy's avatar Chinmoy Committed by GitHub

Added enableFeedback property to BottomNavigationBar (#74043)

parent a65ce5ba
......@@ -275,6 +275,7 @@ class BottomNavigationBar extends StatefulWidget {
this.showSelectedLabels,
this.showUnselectedLabels,
this.mouseCursor,
this.enableFeedback,
}) : assert(items != null),
assert(items.length >= 2),
assert(
......@@ -410,6 +411,16 @@ class BottomNavigationBar extends StatefulWidget {
/// If this property is null, [SystemMouseCursors.click] will be used.
final MouseCursor? mouseCursor;
/// 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.
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
@override
_BottomNavigationBarState createState() => _BottomNavigationBarState();
}
......@@ -434,6 +445,7 @@ class _BottomNavigationTile extends StatelessWidget {
required this.showUnselectedLabels,
this.indexLabel,
required this.mouseCursor,
required this.enableFeedback,
}) : assert(type != null),
assert(item != null),
assert(animation != null),
......@@ -458,6 +470,7 @@ class _BottomNavigationTile extends StatelessWidget {
final bool showSelectedLabels;
final bool showUnselectedLabels;
final MouseCursor mouseCursor;
final bool enableFeedback;
@override
Widget build(BuildContext context) {
......@@ -542,6 +555,7 @@ class _BottomNavigationTile extends StatelessWidget {
Widget result = InkResponse(
onTap: onTap,
mouseCursor: mouseCursor,
enableFeedback: enableFeedback,
child: Padding(
padding: EdgeInsets.only(top: topPadding, bottom: bottomPadding),
child: Column(
......@@ -969,6 +983,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
unselectedIconTheme: widget.unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
selectedLabelStyle: effectiveSelectedLabelStyle,
unselectedLabelStyle: effectiveUnselectedLabelStyle,
enableFeedback: widget.enableFeedback ?? bottomTheme.enableFeedback ?? true,
onTap: () {
if (widget.onTap != null)
widget.onTap!(i);
......
......@@ -43,6 +43,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
this.showSelectedLabels,
this.showUnselectedLabels,
this.type,
this.enableFeedback,
});
/// The color of the [BottomNavigationBar] itself.
......@@ -114,6 +115,11 @@ class BottomNavigationBarThemeData with Diagnosticable {
/// See [BottomNavigationBar.type].
final BottomNavigationBarType? type;
/// If specified, defines the feedback property for [BottomNavigationBar].
///
/// If [BottomNavigationBar.enableFeedback] is provided, [enableFeedback] is ignored.
final bool? enableFeedback;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
BottomNavigationBarThemeData copyWith({
......@@ -128,6 +134,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
bool? showSelectedLabels,
bool? showUnselectedLabels,
BottomNavigationBarType? type,
bool? enableFeedback,
}) {
return BottomNavigationBarThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
......@@ -141,6 +148,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
showSelectedLabels: showSelectedLabels ?? this.showSelectedLabels,
showUnselectedLabels: showUnselectedLabels ?? this.showUnselectedLabels,
type: type ?? this.type,
enableFeedback: enableFeedback ?? this.enableFeedback,
);
}
......@@ -163,6 +171,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
showSelectedLabels: t < 0.5 ? a?.showSelectedLabels : b?.showSelectedLabels,
showUnselectedLabels: t < 0.5 ? a?.showUnselectedLabels : b?.showUnselectedLabels,
type: t < 0.5 ? a?.type : b?.type,
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
);
}
......@@ -180,6 +189,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
showSelectedLabels,
showUnselectedLabels,
type,
enableFeedback,
);
}
......@@ -200,7 +210,8 @@ class BottomNavigationBarThemeData with Diagnosticable {
&& other.unselectedLabelStyle == unselectedLabelStyle
&& other.showSelectedLabels == showSelectedLabels
&& other.showUnselectedLabels == showUnselectedLabels
&& other.type == type;
&& other.type == type
&& other.enableFeedback == enableFeedback;
}
@override
......@@ -217,6 +228,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<bool>('showSelectedLabels', showSelectedLabels, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('showUnselectedLabels', showUnselectedLabels, defaultValue: null));
properties.add(DiagnosticsProperty<BottomNavigationBarType>('type', type, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: null));
}
}
......
......@@ -11,6 +11,7 @@ import 'package:vector_math/vector_math_64.dart' show Vector3;
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
void main() {
testWidgets('BottomNavigationBar callback test', (WidgetTester tester) async {
......@@ -1828,6 +1829,94 @@ void main() {
expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
});
group('feedback', () {
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
});
tearDown(() {
feedback.dispose();
});
Widget feedbackBoilerplate({bool? enableFeedback, bool? enableFeedbackTheme}) {
return MaterialApp(
home: Scaffold(
bottomNavigationBar: BottomNavigationBarTheme(
data: BottomNavigationBarThemeData(
enableFeedback: enableFeedbackTheme,
),
child: BottomNavigationBar(
enableFeedback: enableFeedback,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')),
BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')),
],
),
),
),
);
}
testWidgets('BottomNavigationBar with enabled feedback', (WidgetTester tester) async {
const bool enableFeedback = true;
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
await tester.tap(find.byType(InkResponse).first);
await tester.pumpAndSettle();
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
testWidgets('BottomNavigationBar with disabled feedback', (WidgetTester tester) async {
const bool enableFeedback = false;
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
await tester.tap(find.byType(InkResponse).first);
await tester.pumpAndSettle();
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
});
testWidgets('BottomNavigationBar with enabled feedback by default', (WidgetTester tester) async {
await tester.pumpWidget(feedbackBoilerplate());
await tester.tap(find.byType(InkResponse).first);
await tester.pumpAndSettle();
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
testWidgets('BottomNavigationBar with disabled feedback using BottomNavigationBarTheme', (WidgetTester tester) async {
const bool enableFeedbackTheme = false;
await tester.pumpWidget(feedbackBoilerplate(enableFeedbackTheme: enableFeedbackTheme));
await tester.tap(find.byType(InkResponse).first);
await tester.pumpAndSettle();
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
});
testWidgets('BottomNavigationBar.enableFeedback overrides BottomNavigationBarTheme.enableFeedback', (WidgetTester tester) async {
const bool enableFeedbackTheme = false;
const bool enableFeedback = true;
await tester.pumpWidget(feedbackBoilerplate(
enableFeedbackTheme: enableFeedbackTheme,
enableFeedback: enableFeedback
));
await tester.tap(find.byType(InkResponse).first);
await tester.pumpAndSettle();
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
});
testWidgets('BottomNavigationBar excludes semantics',
(WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(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