Unverified Commit 5ee5766c authored by Hans Muller's avatar Hans Muller Committed by GitHub

Add builder parameter to showDatePicker, showTimePicker (#27703)

parent 1e5d2e55
......@@ -25,6 +25,9 @@ import 'material_localizations.dart';
import 'text_theme.dart';
import 'theme.dart';
// Examples can assume:
// BuildContext context;
/// Initial display mode of the date picker dialog.
///
/// Date picker UI mode for either showing a list of available years or a
......@@ -1111,6 +1114,28 @@ typedef SelectableDayPredicate = bool Function(DateTime day);
/// The [context] argument is passed to [showDialog], the documentation for
/// which discusses how it is used.
///
/// The [builder] parameter can be used to wrap the dialog widget
/// to add inherited widgets like [Theme].
///
/// {@tool sample}
/// Show a date picker with the dark theme.
///
/// ```dart
/// Future<DateTime> selectedDate = showDatePicker(
/// context: context,
/// initialDate: DateTime.now(),
/// firstDate: DateTime(2018),
/// lastDate: DateTime(2030),
/// builder: (BuildContext context, Widget child) {
/// return Theme(
/// data: ThemeData.dark(),
/// child: child,
/// );
/// },
/// );
/// ```
/// {@end-tool}
///
/// The [context], [initialDate], [firstDate], and [lastDate] parameters must
/// not be null.
///
......@@ -1133,6 +1158,7 @@ Future<DateTime> showDatePicker({
DatePickerMode initialDatePickerMode = DatePickerMode.day,
Locale locale,
TextDirection textDirection,
TransitionBuilder builder,
}) async {
assert(initialDate != null);
assert(firstDate != null);
......@@ -1173,6 +1199,8 @@ Future<DateTime> showDatePicker({
return await showDialog<DateTime>(
context: context,
builder: (BuildContext context) => child,
builder: (BuildContext context) {
return builder == null ? child : builder(context, child);
},
);
}
......@@ -22,6 +22,9 @@ import 'theme.dart';
import 'theme_data.dart';
import 'time.dart';
// Examples can assume:
// BuildContext context;
const Duration _kDialAnimateDuration = Duration(milliseconds: 200);
const double _kTwoPi = 2 * math.pi;
const Duration _kVibrateCommitDelay = Duration(milliseconds: 100);
......@@ -1651,33 +1654,77 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
/// The returned Future resolves to the time selected by the user when the user
/// closes the dialog. If the user cancels the dialog, null is returned.
///
/// To show a dialog with [initialTime] equal to the current time:
/// {@tool sample}
/// Show a dialog with [initialTime] equal to the current time.
///
/// ```dart
/// showTimePicker(
/// Future<TimeOfDay> selectedTime = showTimePicker(
/// initialTime: TimeOfDay.now(),
/// context: context,
/// );
/// ```
/// {@end-tool}
///
/// The `context` argument is passed to [showDialog], the documentation for
/// The [context] argument is passed to [showDialog], the documentation for
/// which discusses how it is used.
///
/// The [builder] parameter can be used to wrap the dialog widget
/// to add inherited widgets like [Localizations.override],
/// [Directionality], or [MediaQuery].
///
/// {@tool sample}
/// Show a dialog with the text direction overridden to be [TextDirection.rtl].
///
/// ```dart
/// Future<TimeOfDay> selectedTimeRTL = showTimePicker(
/// context: context,
/// initialTime: TimeOfDay.now(),
/// builder: (BuildContext context, Widget child) {
/// return Directionality(
/// textDirection: TextDirection.rtl,
/// child: child,
/// );
/// },
/// );
/// ```
/// {@end-tool}
///
/// {@tool sample}
/// Show a dialog with time unconditionally displayed in 24 hour format.
///
/// ```dart
/// Future<TimeOfDay> selectedTime24Hour = showTimePicker(
/// context: context,
/// initialTime: TimeOfDay(hour: 10, minute: 47),
/// builder: (BuildContext context, Widget child) {
/// return MediaQuery(
/// data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),
/// child: child,
/// );
/// },
/// );
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [showDatePicker], which shows a dialog that contains a material design
/// date picker.
Future<TimeOfDay> showTimePicker({
@required BuildContext context,
@required TimeOfDay initialTime
@required TimeOfDay initialTime,
TransitionBuilder builder,
}) async {
assert(context != null);
assert(initialTime != null);
assert(debugCheckHasMaterialLocalizations(context));
final Widget dialog = _TimePickerDialog(initialTime: initialTime);
return await showDialog<TimeOfDay>(
context: context,
builder: (BuildContext context) => _TimePickerDialog(initialTime: initialTime),
builder: (BuildContext context) {
return builder == null ? dialog : builder(context, dialog);
},
);
}
......
......@@ -723,4 +723,54 @@ void _tests() {
expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
}
});
testWidgets('builder parameter', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MaterialApp(
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return RaisedButton(
child: const Text('X'),
onPressed: () {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2018),
lastDate: DateTime(2030),
builder: (BuildContext context, Widget child) {
return Directionality(
textDirection: textDirection,
child: child,
);
},
);
},
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame(TextDirection.ltr));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final double ltrOkRight = tester.getBottomRight(find.text('OK')).dx;
await tester.tap(find.text('OK')); // dismiss the dialog
await tester.pumpAndSettle();
await tester.pumpWidget(buildFrame(TextDirection.rtl));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// Verify that the time picker is being laid out RTL.
// We expect the left edge of the 'OK' button in the RTL
// layout to match the gap between right edge of the 'OK'
// button and the right edge of the 800 wide window.
expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight);
});
}
......@@ -505,6 +505,54 @@ void _tests() {
semantics.dispose();
});
testWidgets('builder parameter', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MaterialApp(
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return RaisedButton(
child: const Text('X'),
onPressed: () {
showTimePicker(
context: context,
initialTime: const TimeOfDay(hour: 7, minute: 0),
builder: (BuildContext context, Widget child) {
return Directionality(
textDirection: textDirection,
child: child,
);
},
);
},
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame(TextDirection.ltr));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final double ltrOkRight = tester.getBottomRight(find.text('OK')).dx;
await tester.tap(find.text('OK')); // dismiss the dialog
await tester.pumpAndSettle();
await tester.pumpWidget(buildFrame(TextDirection.rtl));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// Verify that the time picker is being laid out RTL.
// We expect the left edge of the 'OK' button in the RTL
// layout to match the gap between right edge of the 'OK'
// button and the right edge of the 800 wide window.
expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight);
});
}
final Finder findDialPaint = find.descendant(
......
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