Unverified Commit 36c51cb6 authored by Yash Johri's avatar Yash Johri Committed by GitHub

[CheckboxListTile, SwitchListTile, RadioListTile] Adds visualDensity,...

[CheckboxListTile, SwitchListTile, RadioListTile] Adds visualDensity, focusNode and enableFeedback (#89353)

This PR adds visualDensity, focusNode and enableFeedback to:

- CheckboxListTile
- SwitchListTile
- RadioListTile
parent bd8ee41f
......@@ -138,6 +138,9 @@ class CheckboxListTile extends StatelessWidget {
this.tristate = false,
this.shape,
this.selectedTileColor,
this.visualDensity,
this.focusNode,
this.enableFeedback,
}) : assert(tristate != null),
assert(tristate || value != null),
assert(isThreeLine != null),
......@@ -255,6 +258,21 @@ class CheckboxListTile extends StatelessWidget {
/// If non-null, defines the background color when [CheckboxListTile.selected] is true.
final Color? selectedTileColor;
/// Defines how compact the list tile's layout will be.
///
/// {@macro flutter.material.themedata.visualDensity}
final VisualDensity? visualDensity;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
/// {@macro flutter.material.ListTile.enableFeedback}
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
void _handleValueChange() {
assert(onChanged != null);
switch (value) {
......@@ -311,6 +329,9 @@ class CheckboxListTile extends StatelessWidget {
shape: shape,
selectedTileColor: selectedTileColor,
tileColor: tileColor,
visualDensity: visualDensity,
focusNode: focusNode,
enableFeedback: enableFeedback,
),
),
);
......
......@@ -671,11 +671,15 @@ class ListTile extends StatelessWidget {
/// if it's not null and to [Colors.transparent] if it's null.
final Color? selectedTileColor;
/// {@template flutter.material.ListTile.enableFeedback}
/// 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.
///
/// When null, the default value is true.
/// {@endtemplate}
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
......
......@@ -134,6 +134,9 @@ class RadioListTile<T> extends StatelessWidget {
this.shape,
this.tileColor,
this.selectedTileColor,
this.visualDensity,
this.focusNode,
this.enableFeedback,
}) : assert(toggleable != null),
assert(isThreeLine != null),
assert(!isThreeLine || subtitle != null),
......@@ -275,6 +278,21 @@ class RadioListTile<T> extends StatelessWidget {
/// If non-null, defines the background color when [RadioListTile.selected] is true.
final Color? selectedTileColor;
/// Defines how compact the list tile's layout will be.
///
/// {@macro flutter.material.themedata.visualDensity}
final VisualDensity? visualDensity;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
/// {@macro flutter.material.ListTile.enableFeedback}
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
@override
Widget build(BuildContext context) {
final Widget control = Radio<T>(
......@@ -324,6 +342,9 @@ class RadioListTile<T> extends StatelessWidget {
selected: selected,
autofocus: autofocus,
contentPadding: contentPadding,
visualDensity: visualDensity,
focusNode: focusNode,
enableFeedback: enableFeedback,
),
),
);
......
......@@ -143,6 +143,9 @@ class SwitchListTile extends StatelessWidget {
this.controlAffinity = ListTileControlAffinity.platform,
this.shape,
this.selectedTileColor,
this.visualDensity,
this.focusNode,
this.enableFeedback,
}) : _switchListTileType = _SwitchListTileType.material,
assert(value != null),
assert(isThreeLine != null),
......@@ -185,6 +188,9 @@ class SwitchListTile extends StatelessWidget {
this.controlAffinity = ListTileControlAffinity.platform,
this.shape,
this.selectedTileColor,
this.visualDensity,
this.focusNode,
this.enableFeedback,
}) : _switchListTileType = _SwitchListTileType.adaptive,
assert(value != null),
assert(isThreeLine != null),
......@@ -321,6 +327,21 @@ class SwitchListTile extends StatelessWidget {
/// If non-null, defines the background color when [SwitchListTile.selected] is true.
final Color? selectedTileColor;
/// Defines how compact the list tile's layout will be.
///
/// {@macro flutter.material.themedata.visualDensity}
final VisualDensity? visualDensity;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
/// {@macro flutter.material.ListTile.enableFeedback}
///
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
@override
Widget build(BuildContext context) {
final Widget control;
......@@ -386,6 +407,9 @@ class SwitchListTile extends StatelessWidget {
autofocus: autofocus,
shape: shape,
tileColor: tileColor,
visualDensity: visualDensity,
focusNode: focusNode,
enableFeedback: enableFeedback,
),
),
);
......
......@@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import 'feedback_tester.dart';
Widget wrap({ required Widget child }) {
return MediaQuery(
......@@ -319,4 +320,90 @@ void main() {
await tester.pumpWidget(buildFrame(activeColor: activeColor));
expect(textColor('title'), activeColor);
});
testWidgets('CheckboxListTile respects visualDensity', (WidgetTester tester) async {
const Key key = Key('test');
Future<void> buildTest(VisualDensity visualDensity) async {
return tester.pumpWidget(
wrap(
child: Center(
child: CheckboxListTile(
key: key,
value: false,
onChanged: (bool? value) {},
autofocus: true,
visualDensity: visualDensity,
),
),
),
);
}
await buildTest(VisualDensity.standard);
final RenderBox box = tester.renderObject(find.byKey(key));
await tester.pumpAndSettle();
expect(box.size, equals(const Size(800, 56)));
});
testWidgets('CheckboxListTile respects focusNode', (WidgetTester tester) async {
final GlobalKey childKey = GlobalKey();
await tester.pumpWidget(
wrap(
child: Center(
child: CheckboxListTile(
value: false,
title: Text('A', key: childKey),
onChanged: (bool? value) {},
),
),
),
);
await tester.pump();
final FocusNode tileNode = Focus.of(childKey.currentContext!);
tileNode.requestFocus();
await tester.pump(); // Let the focus take effect.
expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isTrue);
expect(tileNode.hasPrimaryFocus, isTrue);
});
group('feedback', () {
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
});
tearDown(() {
feedback.dispose();
});
testWidgets('CheckboxListTile respects enableFeedback', (WidgetTester tester) async {
Future<void> buildTest(bool enableFeedback) async {
return tester.pumpWidget(
wrap(
child: Center(
child: CheckboxListTile(
value: false,
onChanged: (bool? value) {},
enableFeedback: enableFeedback,
),
),
),
);
}
await buildTest(false);
await tester.tap(find.byType(CheckboxListTile));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
await buildTest(true);
await tester.tap(find.byType(CheckboxListTile));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
});
}
......@@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
Widget wrap({Widget? child}) {
return MediaQuery(
......@@ -741,4 +742,96 @@ void main() {
await tester.pumpWidget(buildFrame(activeColor: activeColor));
expect(textColor('title'), activeColor);
});
testWidgets('RadioListTile respects visualDensity', (WidgetTester tester) async {
const Key key = Key('test');
Future<void> buildTest(VisualDensity visualDensity) async {
return tester.pumpWidget(
wrap(
child: Center(
child: RadioListTile<bool>(
key: key,
value: false,
groupValue: true,
onChanged: (bool? value) {},
autofocus: true,
visualDensity: visualDensity,
),
),
),
);
}
await buildTest(VisualDensity.standard);
final RenderBox box = tester.renderObject(find.byKey(key));
await tester.pumpAndSettle();
expect(box.size, equals(const Size(800, 56)));
});
testWidgets('RadioListTile respects focusNode', (WidgetTester tester) async {
final GlobalKey childKey = GlobalKey();
await tester.pumpWidget(
wrap(
child: Center(
child: RadioListTile<bool>(
value: false,
groupValue: true,
title: Text('A', key: childKey),
onChanged: (bool? value) {},
),
),
),
);
await tester.pump();
final FocusNode tileNode = Focus.of(childKey.currentContext!);
tileNode.requestFocus();
await tester.pump(); // Let the focus take effect.
expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isTrue);
expect(tileNode.hasPrimaryFocus, isTrue);
});
group('feedback', () {
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
});
tearDown(() {
feedback.dispose();
});
testWidgets('RadioListTile respects enableFeedback', (WidgetTester tester) async {
const Key key = Key('test');
Future<void> buildTest(bool enableFeedback) async {
return tester.pumpWidget(
wrap(
child: Center(
child: RadioListTile<bool>(
key: key,
value: false,
groupValue: true,
selected: true,
onChanged: (bool? value) {},
enableFeedback: enableFeedback,
),
),
),
);
}
await buildTest(false);
await tester.tap(find.byKey(key));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
await buildTest(true);
await tester.tap(find.byKey(key));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
});
}
......@@ -10,6 +10,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
Widget wrap({ required Widget child }) {
return MediaQuery(
......@@ -432,4 +433,90 @@ void main() {
await tester.pumpWidget(buildFrame(activeColor: activeColor));
expect(textColor('title'), activeColor);
});
testWidgets('SwitchListTile respects visualDensity', (WidgetTester tester) async {
const Key key = Key('test');
Future<void> buildTest(VisualDensity visualDensity) async {
return tester.pumpWidget(
wrap(
child: Center(
child: SwitchListTile(
key: key,
value: false,
onChanged: (bool? value) {},
autofocus: true,
visualDensity: visualDensity,
),
),
),
);
}
await buildTest(VisualDensity.standard);
final RenderBox box = tester.renderObject(find.byKey(key));
await tester.pumpAndSettle();
expect(box.size, equals(const Size(800, 56)));
});
testWidgets('SwitchListTile respects focusNode', (WidgetTester tester) async {
final GlobalKey childKey = GlobalKey();
await tester.pumpWidget(
wrap(
child: Center(
child: SwitchListTile(
value: false,
title: Text('A', key: childKey),
onChanged: (bool? value) {},
),
),
),
);
await tester.pump();
final FocusNode tileNode = Focus.of(childKey.currentContext!);
tileNode.requestFocus();
await tester.pump(); // Let the focus take effect.
expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isTrue);
expect(tileNode.hasPrimaryFocus, isTrue);
});
group('feedback', () {
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
});
tearDown(() {
feedback.dispose();
});
testWidgets('SwitchListTile respects enableFeedback', (WidgetTester tester) async {
Future<void> buildTest(bool enableFeedback) async {
return tester.pumpWidget(
wrap(
child: Center(
child: SwitchListTile(
value: false,
onChanged: (bool? value) {},
enableFeedback: enableFeedback,
),
),
),
);
}
await buildTest(false);
await tester.tap(find.byType(SwitchListTile));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 0);
expect(feedback.hapticCount, 0);
await buildTest(true);
await tester.tap(find.byType(SwitchListTile));
await tester.pump(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);
expect(feedback.hapticCount, 0);
});
});
}
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