Fix memory leaks in DateRangePickerDialog. (#136034)
This PR mainly fixes several memory leaks in the `DateRangePickerDialog`. ### Description - Fixes https://github.com/flutter/flutter/issues/136033 by: 1) adding a disposal of several `RestorableValue`; 2) creating a separate `_DayItem` stateful widget that creates/updates/disposes internal `MaterialStatesController`. - Marks https://github.com/flutter/flutter/issues/136036. ### Tests - Updates `test/material/date_picker_theme_test.dart` to use `testWidgetsWithLeakTracking`; - Updates `test/material/date_range_picker_test.dart` to use `testWidgetsWithLeakTracking`.
This commit is contained in:
parent
670e6ba129
commit
d76e3abf10
@ -1353,6 +1353,15 @@ class _DateRangePickerDialogState extends State<DateRangePickerDialog> with Rest
|
|||||||
registerForRestoration(_autoValidate, 'autovalidate');
|
registerForRestoration(_autoValidate, 'autovalidate');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_entryMode.dispose();
|
||||||
|
_selectedStart.dispose();
|
||||||
|
_selectedEnd.dispose();
|
||||||
|
_autoValidate.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
void _handleOk() {
|
void _handleOk() {
|
||||||
if (_entryMode.value == DatePickerEntryMode.input || _entryMode.value == DatePickerEntryMode.inputOnly) {
|
if (_entryMode.value == DatePickerEntryMode.input || _entryMode.value == DatePickerEntryMode.inputOnly) {
|
||||||
final _InputDateRangePickerState picker = _inputPickerKey.currentState!;
|
final _InputDateRangePickerState picker = _inputPickerKey.currentState!;
|
||||||
@ -2368,145 +2377,34 @@ class _MonthItemState extends State<_MonthItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDayItem(BuildContext context, DateTime dayToBuild, int firstDayOffset, int daysInMonth) {
|
Widget _buildDayItem(BuildContext context, DateTime dayToBuild, int firstDayOffset, int daysInMonth) {
|
||||||
final ThemeData theme = Theme.of(context);
|
|
||||||
final ColorScheme colorScheme = theme.colorScheme;
|
|
||||||
final TextTheme textTheme = theme.textTheme;
|
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
|
||||||
final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context);
|
|
||||||
final DatePickerThemeData defaults = DatePickerTheme.defaults(context);
|
|
||||||
final TextDirection textDirection = Directionality.of(context);
|
|
||||||
final Color highlightColor = _highlightColor(context);
|
|
||||||
final int day = dayToBuild.day;
|
final int day = dayToBuild.day;
|
||||||
|
|
||||||
final bool isDisabled = dayToBuild.isAfter(widget.lastDate) || dayToBuild.isBefore(widget.firstDate);
|
final bool isDisabled = dayToBuild.isAfter(widget.lastDate) || dayToBuild.isBefore(widget.firstDate);
|
||||||
|
|
||||||
BoxDecoration? decoration;
|
|
||||||
TextStyle? itemStyle = textTheme.bodyMedium;
|
|
||||||
|
|
||||||
final bool isRangeSelected = widget.selectedDateStart != null && widget.selectedDateEnd != null;
|
final bool isRangeSelected = widget.selectedDateStart != null && widget.selectedDateEnd != null;
|
||||||
final bool isSelectedDayStart = widget.selectedDateStart != null && dayToBuild.isAtSameMomentAs(widget.selectedDateStart!);
|
final bool isSelectedDayStart = widget.selectedDateStart != null && dayToBuild.isAtSameMomentAs(widget.selectedDateStart!);
|
||||||
final bool isSelectedDayEnd = widget.selectedDateEnd != null && dayToBuild.isAtSameMomentAs(widget.selectedDateEnd!);
|
final bool isSelectedDayEnd = widget.selectedDateEnd != null && dayToBuild.isAtSameMomentAs(widget.selectedDateEnd!);
|
||||||
final bool isInRange = isRangeSelected &&
|
final bool isInRange = isRangeSelected &&
|
||||||
dayToBuild.isAfter(widget.selectedDateStart!) &&
|
dayToBuild.isAfter(widget.selectedDateStart!) &&
|
||||||
dayToBuild.isBefore(widget.selectedDateEnd!);
|
dayToBuild.isBefore(widget.selectedDateEnd!);
|
||||||
|
final bool isOneDayRange = isRangeSelected && widget.selectedDateStart == widget.selectedDateEnd;
|
||||||
|
final bool isToday = DateUtils.isSameDay(widget.currentDate, dayToBuild);
|
||||||
|
|
||||||
T? effectiveValue<T>(T? Function(DatePickerThemeData? theme) getProperty) {
|
return _DayItem(
|
||||||
return getProperty(datePickerTheme) ?? getProperty(defaults);
|
day: dayToBuild,
|
||||||
}
|
|
||||||
|
|
||||||
T? resolve<T>(MaterialStateProperty<T>? Function(DatePickerThemeData? theme) getProperty, Set<MaterialState> states) {
|
|
||||||
return effectiveValue(
|
|
||||||
(DatePickerThemeData? theme) {
|
|
||||||
return getProperty(theme)?.resolve(states);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<MaterialState> states = <MaterialState>{
|
|
||||||
if (isDisabled) MaterialState.disabled,
|
|
||||||
if (isSelectedDayStart || isSelectedDayEnd) MaterialState.selected,
|
|
||||||
};
|
|
||||||
|
|
||||||
final Color? dayForegroundColor = resolve<Color?>((DatePickerThemeData? theme) => theme?.dayForegroundColor, states);
|
|
||||||
final Color? dayBackgroundColor = resolve<Color?>((DatePickerThemeData? theme) => theme?.dayBackgroundColor, states);
|
|
||||||
final MaterialStateProperty<Color?> dayOverlayColor = MaterialStateProperty.resolveWith<Color?>(
|
|
||||||
(Set<MaterialState> states) => effectiveValue(
|
|
||||||
(DatePickerThemeData? theme) =>
|
|
||||||
isInRange
|
|
||||||
? theme?.rangeSelectionOverlayColor?.resolve(states)
|
|
||||||
: theme?.dayOverlayColor?.resolve(states),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
_HighlightPainter? highlightPainter;
|
|
||||||
|
|
||||||
if (isSelectedDayStart || isSelectedDayEnd) {
|
|
||||||
// The selected start and end dates gets a circle background
|
|
||||||
// highlight, and a contrasting text color.
|
|
||||||
itemStyle = textTheme.bodyMedium?.apply(color: dayForegroundColor);
|
|
||||||
decoration = BoxDecoration(
|
|
||||||
color: dayBackgroundColor,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isRangeSelected && widget.selectedDateStart != widget.selectedDateEnd) {
|
|
||||||
final _HighlightPainterStyle style = isSelectedDayStart
|
|
||||||
? _HighlightPainterStyle.highlightTrailing
|
|
||||||
: _HighlightPainterStyle.highlightLeading;
|
|
||||||
highlightPainter = _HighlightPainter(
|
|
||||||
color: highlightColor,
|
|
||||||
style: style,
|
|
||||||
textDirection: textDirection,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (isInRange) {
|
|
||||||
// The days within the range get a light background highlight.
|
|
||||||
highlightPainter = _HighlightPainter(
|
|
||||||
color: highlightColor,
|
|
||||||
style: _HighlightPainterStyle.highlightAll,
|
|
||||||
textDirection: textDirection,
|
|
||||||
);
|
|
||||||
} else if (isDisabled) {
|
|
||||||
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.onSurface.withOpacity(0.38));
|
|
||||||
} else if (DateUtils.isSameDay(widget.currentDate, dayToBuild)) {
|
|
||||||
// The current day gets a different text color and a circle stroke
|
|
||||||
// border.
|
|
||||||
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.primary);
|
|
||||||
decoration = BoxDecoration(
|
|
||||||
border: Border.all(color: colorScheme.primary),
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want the day of month to be spoken first irrespective of the
|
|
||||||
// locale-specific preferences or TextDirection. This is because
|
|
||||||
// an accessibility user is more likely to be interested in the
|
|
||||||
// day of month before the rest of the date, as they are looking
|
|
||||||
// for the day of month. To do that we prepend day of month to the
|
|
||||||
// formatted full date.
|
|
||||||
final String semanticLabelSuffix = DateUtils.isSameDay(widget.currentDate, dayToBuild) ? ', ${localizations.currentDateLabel}' : '';
|
|
||||||
String semanticLabel = '${localizations.formatDecimal(day)}, ${localizations.formatFullDate(dayToBuild)}$semanticLabelSuffix';
|
|
||||||
if (isSelectedDayStart) {
|
|
||||||
semanticLabel = localizations.dateRangeStartDateSemanticLabel(semanticLabel);
|
|
||||||
} else if (isSelectedDayEnd) {
|
|
||||||
semanticLabel = localizations.dateRangeEndDateSemanticLabel(semanticLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget dayWidget = Container(
|
|
||||||
decoration: decoration,
|
|
||||||
child: Center(
|
|
||||||
child: Semantics(
|
|
||||||
label: semanticLabel,
|
|
||||||
selected: isSelectedDayStart || isSelectedDayEnd,
|
|
||||||
child: ExcludeSemantics(
|
|
||||||
child: Text(localizations.formatDecimal(day), style: itemStyle),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (highlightPainter != null) {
|
|
||||||
dayWidget = CustomPaint(
|
|
||||||
painter: highlightPainter,
|
|
||||||
child: dayWidget,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDisabled) {
|
|
||||||
dayWidget = InkResponse(
|
|
||||||
focusNode: _dayFocusNodes[day - 1],
|
focusNode: _dayFocusNodes[day - 1],
|
||||||
onTap: () => widget.onChanged(dayToBuild),
|
onChanged: widget.onChanged,
|
||||||
radius: _monthItemRowHeight / 2 + 4,
|
|
||||||
statesController: MaterialStatesController(states),
|
|
||||||
overlayColor: dayOverlayColor,
|
|
||||||
onFocusChange: _dayFocusChanged,
|
onFocusChange: _dayFocusChanged,
|
||||||
child: dayWidget,
|
highlightColor: _highlightColor(context),
|
||||||
|
isDisabled: isDisabled,
|
||||||
|
isRangeSelected: isRangeSelected,
|
||||||
|
isSelectedDayStart: isSelectedDayStart,
|
||||||
|
isSelectedDayEnd: isSelectedDayEnd,
|
||||||
|
isInRange: isInRange,
|
||||||
|
isOneDayRange: isOneDayRange,
|
||||||
|
isToday: isToday,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dayWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildEdgeContainer(BuildContext context, bool isHighlighted) {
|
Widget _buildEdgeContainer(BuildContext context, bool isHighlighted) {
|
||||||
return Container(color: isHighlighted ? _highlightColor(context) : null);
|
return Container(color: isHighlighted ? _highlightColor(context) : null);
|
||||||
}
|
}
|
||||||
@ -2618,6 +2516,194 @@ class _MonthItemState extends State<_MonthItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DayItem extends StatefulWidget {
|
||||||
|
const _DayItem({
|
||||||
|
required this.day,
|
||||||
|
required this.focusNode,
|
||||||
|
required this.onChanged,
|
||||||
|
required this.onFocusChange,
|
||||||
|
required this.highlightColor,
|
||||||
|
required this.isDisabled,
|
||||||
|
required this.isRangeSelected,
|
||||||
|
required this.isSelectedDayStart,
|
||||||
|
required this.isSelectedDayEnd,
|
||||||
|
required this.isInRange,
|
||||||
|
required this.isOneDayRange,
|
||||||
|
required this.isToday,
|
||||||
|
});
|
||||||
|
|
||||||
|
final DateTime day;
|
||||||
|
|
||||||
|
final FocusNode focusNode;
|
||||||
|
|
||||||
|
final ValueChanged<DateTime> onChanged;
|
||||||
|
|
||||||
|
final ValueChanged<bool> onFocusChange;
|
||||||
|
|
||||||
|
final Color highlightColor;
|
||||||
|
|
||||||
|
final bool isDisabled;
|
||||||
|
|
||||||
|
final bool isRangeSelected;
|
||||||
|
|
||||||
|
final bool isSelectedDayStart;
|
||||||
|
|
||||||
|
final bool isSelectedDayEnd;
|
||||||
|
|
||||||
|
final bool isInRange;
|
||||||
|
|
||||||
|
final bool isOneDayRange;
|
||||||
|
|
||||||
|
final bool isToday;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_DayItem> createState() => _DayItemState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DayItemState extends State<_DayItem> {
|
||||||
|
final MaterialStatesController _statesController = MaterialStatesController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_statesController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final ThemeData theme = Theme.of(context);
|
||||||
|
final ColorScheme colorScheme = theme.colorScheme;
|
||||||
|
final TextTheme textTheme = theme.textTheme;
|
||||||
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
|
final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context);
|
||||||
|
final DatePickerThemeData defaults = DatePickerTheme.defaults(context);
|
||||||
|
final TextDirection textDirection = Directionality.of(context);
|
||||||
|
final Color highlightColor = widget.highlightColor;
|
||||||
|
|
||||||
|
BoxDecoration? decoration;
|
||||||
|
TextStyle? itemStyle = textTheme.bodyMedium;
|
||||||
|
|
||||||
|
T? effectiveValue<T>(T? Function(DatePickerThemeData? theme) getProperty) {
|
||||||
|
return getProperty(datePickerTheme) ?? getProperty(defaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
T? resolve<T>(MaterialStateProperty<T>? Function(DatePickerThemeData? theme) getProperty, Set<MaterialState> states) {
|
||||||
|
return effectiveValue(
|
||||||
|
(DatePickerThemeData? theme) {
|
||||||
|
return getProperty(theme)?.resolve(states);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<MaterialState> states = <MaterialState>{
|
||||||
|
if (widget.isDisabled) MaterialState.disabled,
|
||||||
|
if (widget.isSelectedDayStart || widget.isSelectedDayEnd) MaterialState.selected,
|
||||||
|
};
|
||||||
|
|
||||||
|
_statesController.value = states;
|
||||||
|
|
||||||
|
final Color? dayForegroundColor = resolve<Color?>((DatePickerThemeData? theme) => theme?.dayForegroundColor, states);
|
||||||
|
final Color? dayBackgroundColor = resolve<Color?>((DatePickerThemeData? theme) => theme?.dayBackgroundColor, states);
|
||||||
|
final MaterialStateProperty<Color?> dayOverlayColor = MaterialStateProperty.resolveWith<Color?>(
|
||||||
|
(Set<MaterialState> states) => effectiveValue(
|
||||||
|
(DatePickerThemeData? theme) => widget.isInRange
|
||||||
|
? theme?.rangeSelectionOverlayColor?.resolve(states)
|
||||||
|
: theme?.dayOverlayColor?.resolve(states),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
_HighlightPainter? highlightPainter;
|
||||||
|
|
||||||
|
if (widget.isSelectedDayStart || widget.isSelectedDayEnd) {
|
||||||
|
// The selected start and end dates gets a circle background
|
||||||
|
// highlight, and a contrasting text color.
|
||||||
|
itemStyle = textTheme.bodyMedium?.apply(color: dayForegroundColor);
|
||||||
|
decoration = BoxDecoration(
|
||||||
|
color: dayBackgroundColor,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.isRangeSelected && !widget.isOneDayRange) {
|
||||||
|
final _HighlightPainterStyle style = widget.isSelectedDayStart
|
||||||
|
? _HighlightPainterStyle.highlightTrailing
|
||||||
|
: _HighlightPainterStyle.highlightLeading;
|
||||||
|
highlightPainter = _HighlightPainter(
|
||||||
|
color: highlightColor,
|
||||||
|
style: style,
|
||||||
|
textDirection: textDirection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (widget.isInRange) {
|
||||||
|
// The days within the range get a light background highlight.
|
||||||
|
highlightPainter = _HighlightPainter(
|
||||||
|
color: highlightColor,
|
||||||
|
style: _HighlightPainterStyle.highlightAll,
|
||||||
|
textDirection: textDirection,
|
||||||
|
);
|
||||||
|
} else if (widget.isDisabled) {
|
||||||
|
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.onSurface.withOpacity(0.38));
|
||||||
|
} else if (widget.isToday) {
|
||||||
|
// The current day gets a different text color and a circle stroke
|
||||||
|
// border.
|
||||||
|
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.primary);
|
||||||
|
decoration = BoxDecoration(
|
||||||
|
border: Border.all(color: colorScheme.primary),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String dayText = localizations.formatDecimal(widget.day.day);
|
||||||
|
|
||||||
|
// We want the day of month to be spoken first irrespective of the
|
||||||
|
// locale-specific preferences or TextDirection. This is because
|
||||||
|
// an accessibility user is more likely to be interested in the
|
||||||
|
// day of month before the rest of the date, as they are looking
|
||||||
|
// for the day of month. To do that we prepend day of month to the
|
||||||
|
// formatted full date.
|
||||||
|
final String semanticLabelSuffix = widget.isToday ? ', ${localizations.currentDateLabel}' : '';
|
||||||
|
String semanticLabel = '$dayText, ${localizations.formatFullDate(widget.day)}$semanticLabelSuffix';
|
||||||
|
if (widget.isSelectedDayStart) {
|
||||||
|
semanticLabel = localizations.dateRangeStartDateSemanticLabel(semanticLabel);
|
||||||
|
} else if (widget.isSelectedDayEnd) {
|
||||||
|
semanticLabel = localizations.dateRangeEndDateSemanticLabel(semanticLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget dayWidget = Container(
|
||||||
|
decoration: decoration,
|
||||||
|
child: Center(
|
||||||
|
child: Semantics(
|
||||||
|
label: semanticLabel,
|
||||||
|
selected: widget.isSelectedDayStart || widget.isSelectedDayEnd,
|
||||||
|
child: ExcludeSemantics(
|
||||||
|
child: Text(dayText, style: itemStyle),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (highlightPainter != null) {
|
||||||
|
dayWidget = CustomPaint(
|
||||||
|
painter: highlightPainter,
|
||||||
|
child: dayWidget,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!widget.isDisabled) {
|
||||||
|
dayWidget = InkResponse(
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
onTap: () => widget.onChanged(widget.day),
|
||||||
|
radius: _monthItemRowHeight / 2 + 4,
|
||||||
|
statesController: _statesController,
|
||||||
|
overlayColor: dayOverlayColor,
|
||||||
|
onFocusChange: widget.onFocusChange,
|
||||||
|
child: dayWidget,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dayWidget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines which style to use to paint the highlight.
|
/// Determines which style to use to paint the highlight.
|
||||||
enum _HighlightPainterStyle {
|
enum _HighlightPainterStyle {
|
||||||
/// Paints nothing.
|
/// Paints nothing.
|
||||||
|
@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const DatePickerThemeData datePickerTheme = DatePickerThemeData(
|
const DatePickerThemeData datePickerTheme = DatePickerThemeData(
|
||||||
@ -136,7 +137,7 @@ void main() {
|
|||||||
expect(theme.confirmButtonStyle, null);
|
expect(theme.confirmButtonStyle, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
|
||||||
late final DatePickerThemeData m3; // M3 Defaults
|
late final DatePickerThemeData m3; // M3 Defaults
|
||||||
late final ThemeData theme;
|
late final ThemeData theme;
|
||||||
late final ColorScheme colorScheme;
|
late final ColorScheme colorScheme;
|
||||||
@ -213,7 +214,7 @@ void main() {
|
|||||||
expect(m3.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
expect(m3.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
|
||||||
late final DatePickerThemeData m2; // M2 defaults
|
late final DatePickerThemeData m2; // M2 defaults
|
||||||
late final ThemeData theme;
|
late final ThemeData theme;
|
||||||
late final ColorScheme colorScheme;
|
late final ColorScheme colorScheme;
|
||||||
@ -282,7 +283,7 @@ void main() {
|
|||||||
expect(m2.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
expect(m2.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
||||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||||
const DatePickerThemeData().debugFillProperties(builder);
|
const DatePickerThemeData().debugFillProperties(builder);
|
||||||
|
|
||||||
@ -294,7 +295,7 @@ void main() {
|
|||||||
expect(description, <String>[]);
|
expect(description, <String>[]);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerThemeData implements debugFillProperties', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerThemeData implements debugFillProperties', (WidgetTester tester) async {
|
||||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||||
|
|
||||||
datePickerTheme.debugFillProperties(builder);
|
datePickerTheme.debugFillProperties(builder);
|
||||||
@ -344,7 +345,7 @@ void main() {
|
|||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -445,7 +446,7 @@ void main() {
|
|||||||
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -492,7 +493,7 @@ void main() {
|
|||||||
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -551,9 +552,14 @@ void main() {
|
|||||||
await gesture.moveTo(tester.getCenter(find.text('18')));
|
await gesture.moveTo(tester.getCenter(find.text('18')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(inkFeatures, paints..circle(color: datePickerTheme.rangeSelectionOverlayColor?.resolve(<MaterialState>{})));
|
expect(inkFeatures, paints..circle(color: datePickerTheme.rangeSelectionOverlayColor?.resolve(<MaterialState>{})));
|
||||||
});
|
},
|
||||||
|
leakTrackingTestConfig: const LeakTrackingTestConfig(
|
||||||
|
// TODO(ksokolovskyi): remove after fixing
|
||||||
|
// https://github.com/flutter/flutter/issues/136036
|
||||||
|
notDisposedAllowList: <String, int?> {'AnnotatedRegionLayer<SystemUiOverlayStyle>': 2},
|
||||||
|
));
|
||||||
|
|
||||||
testWidgets('Dividers use DatePickerThemeData.dividerColor', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Dividers use DatePickerThemeData.dividerColor', (WidgetTester tester) async {
|
||||||
Future<void> showPicker(WidgetTester tester, Size size) async {
|
Future<void> showPicker(WidgetTester tester, Size size) async {
|
||||||
tester.view.physicalSize = size;
|
tester.view.physicalSize = size;
|
||||||
tester.view.devicePixelRatio = 1.0;
|
tester.view.devicePixelRatio = 1.0;
|
||||||
@ -594,7 +600,7 @@ void main() {
|
|||||||
expect(horizontalDivider.color, datePickerTheme.dividerColor);
|
expect(horizontalDivider.color, datePickerTheme.dividerColor);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets(
|
testWidgetsWithLeakTracking(
|
||||||
'DatePicker uses ThemeData.inputDecorationTheme properties '
|
'DatePicker uses ThemeData.inputDecorationTheme properties '
|
||||||
'which are null in DatePickerThemeData.inputDecorationTheme',
|
'which are null in DatePickerThemeData.inputDecorationTheme',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
@ -650,7 +656,7 @@ void main() {
|
|||||||
expect(inputDecoration.border , const OutlineInputBorder());
|
expect(inputDecoration.border , const OutlineInputBorder());
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog resolves DatePickerTheme.dayOverlayColor states', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerDialog resolves DatePickerTheme.dayOverlayColor states', (WidgetTester tester) async {
|
||||||
final MaterialStateProperty<Color> dayOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
final MaterialStateProperty<Color> dayOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return const Color(0xff00ff00);
|
return const Color(0xff00ff00);
|
||||||
@ -742,7 +748,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog resolves DatePickerTheme.yearOverlayColor states', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerDialog resolves DatePickerTheme.yearOverlayColor states', (WidgetTester tester) async {
|
||||||
final MaterialStateProperty<Color> yearOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
final MaterialStateProperty<Color> yearOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return const Color(0xff00ff00);
|
return const Color(0xff00ff00);
|
||||||
@ -824,7 +830,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DateRangePickerDialog resolves DatePickerTheme.rangeSelectionOverlayColor states', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DateRangePickerDialog resolves DatePickerTheme.rangeSelectionOverlayColor states', (WidgetTester tester) async {
|
||||||
final MaterialStateProperty<Color> rangeSelectionOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
final MaterialStateProperty<Color> rangeSelectionOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return const Color(0xff00ff00);
|
return const Color(0xff00ff00);
|
||||||
@ -896,5 +902,10 @@ void main() {
|
|||||||
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
|
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
leakTrackingTestConfig: const LeakTrackingTestConfig(
|
||||||
|
// TODO(ksokolovskyi): remove after fixing
|
||||||
|
// https://github.com/flutter/flutter/issues/136036
|
||||||
|
notDisposedAllowList: <String, int?> {'AnnotatedRegionLayer<SystemUiOverlayStyle>': 2},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
|
||||||
import 'feedback_tester.dart';
|
import 'feedback_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -111,7 +112,7 @@ void main() {
|
|||||||
await callback(range);
|
await callback(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
testWidgets('Default layout (calendar mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default layout (calendar mode)', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Finder helpText = find.text('Select range');
|
final Finder helpText = find.text('Select range');
|
||||||
final Finder firstDateHeaderText = find.text('Jan 15');
|
final Finder firstDateHeaderText = find.text('Jan 15');
|
||||||
@ -173,7 +174,7 @@ void main() {
|
|||||||
}, useMaterial3: true);
|
}, useMaterial3: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default Dialog properties (calendar mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default Dialog properties (calendar mode)', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Material dialogMaterial = tester.widget<Material>(
|
final Material dialogMaterial = tester.widget<Material>(
|
||||||
@ -193,7 +194,7 @@ void main() {
|
|||||||
}, useMaterial3: theme.useMaterial3);
|
}, useMaterial3: theme.useMaterial3);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Material dialogMaterial = tester.widget<Material>(
|
final Material dialogMaterial = tester.widget<Material>(
|
||||||
@ -213,7 +214,7 @@ void main() {
|
|||||||
}, useMaterial3: theme.useMaterial3);
|
}, useMaterial3: theme.useMaterial3);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Scaffold and AppBar defaults', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Scaffold and AppBar defaults', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Scaffold scaffold = tester.widget<Scaffold>(find.byType(Scaffold));
|
final Scaffold scaffold = tester.widget<Scaffold>(find.byType(Scaffold));
|
||||||
@ -244,14 +245,14 @@ void main() {
|
|||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async { }, useMaterial3: true);
|
await preparePicker(tester, (Future<DateTimeRange?> range) async { }, useMaterial3: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
testWidgets('portrait', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('portrait', (WidgetTester tester) async {
|
||||||
await showPicker(tester, kCommonScreenSizePortrait);
|
await showPicker(tester, kCommonScreenSizePortrait);
|
||||||
expect(tester.widget<Text>(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 32);
|
expect(tester.widget<Text>(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 32);
|
||||||
await tester.tap(find.text('Cancel'));
|
await tester.tap(find.text('Cancel'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('landscape', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('landscape', (WidgetTester tester) async {
|
||||||
await showPicker(tester, kCommonScreenSizeLandscape);
|
await showPicker(tester, kCommonScreenSizeLandscape);
|
||||||
expect(tester.widget<Text>(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 24);
|
expect(tester.widget<Text>(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 24);
|
||||||
await tester.tap(find.text('Cancel'));
|
await tester.tap(find.text('Cancel'));
|
||||||
@ -259,7 +260,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Save and help text is used', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Save and help text is used', (WidgetTester tester) async {
|
||||||
helpText = 'help';
|
helpText = 'help';
|
||||||
saveText = 'make it so';
|
saveText = 'make it so';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -268,14 +269,14 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Material3 has sentence case labels', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Material3 has sentence case labels', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.text('Save'), findsOneWidget);
|
expect(find.text('Save'), findsOneWidget);
|
||||||
expect(find.text('Select range'), findsOneWidget);
|
expect(find.text('Select range'), findsOneWidget);
|
||||||
}, useMaterial3: true);
|
}, useMaterial3: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Initial date is the default', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('SAVE'));
|
await tester.tap(find.text('SAVE'));
|
||||||
expect(
|
expect(
|
||||||
@ -288,7 +289,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Last month header should be visible if last date is selected', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Last month header should be visible if last date is selected', (WidgetTester tester) async {
|
||||||
firstDate = DateTime(2015);
|
firstDate = DateTime(2015);
|
||||||
lastDate = DateTime(2016, DateTime.december, 31);
|
lastDate = DateTime(2016, DateTime.december, 31);
|
||||||
initialDateRange = DateTimeRange(
|
initialDateRange = DateTimeRange(
|
||||||
@ -302,7 +303,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('First month header should be visible if first date is selected', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('First month header should be visible if first date is selected', (WidgetTester tester) async {
|
||||||
firstDate = DateTime(2015);
|
firstDate = DateTime(2015);
|
||||||
lastDate = DateTime(2016, DateTime.december, 31);
|
lastDate = DateTime(2016, DateTime.december, 31);
|
||||||
initialDateRange = DateTimeRange(
|
initialDateRange = DateTimeRange(
|
||||||
@ -317,7 +318,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Current month header should be visible if no date is selected', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Current month header should be visible if no date is selected', (WidgetTester tester) async {
|
||||||
firstDate = DateTime(2015);
|
firstDate = DateTime(2015);
|
||||||
lastDate = DateTime(2016, DateTime.december, 31);
|
lastDate = DateTime(2016, DateTime.december, 31);
|
||||||
currentDate = DateTime(2016, DateTime.september);
|
currentDate = DateTime(2016, DateTime.september);
|
||||||
@ -331,14 +332,14 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can cancel', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can cancel', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.byIcon(Icons.close));
|
await tester.tap(find.byIcon(Icons.close));
|
||||||
expect(await range, isNull);
|
expect(await range, isNull);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can select a range', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can select a range', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('12').first);
|
await tester.tap(find.text('12').first);
|
||||||
await tester.tap(find.text('14').first);
|
await tester.tap(find.text('14').first);
|
||||||
@ -350,7 +351,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tapping earlier date resets selected range', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Tapping earlier date resets selected range', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('12').first);
|
await tester.tap(find.text('12').first);
|
||||||
await tester.tap(find.text('11').first);
|
await tester.tap(find.text('11').first);
|
||||||
@ -363,7 +364,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can select single day range', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can select single day range', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('12').first);
|
await tester.tap(find.text('12').first);
|
||||||
await tester.tap(find.text('12').first);
|
await tester.tap(find.text('12').first);
|
||||||
@ -375,7 +376,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Cannot select a day outside bounds', (WidgetTester tester) async {
|
||||||
initialDateRange = DateTimeRange(
|
initialDateRange = DateTimeRange(
|
||||||
start: DateTime(2017, DateTime.january, 13),
|
start: DateTime(2017, DateTime.january, 13),
|
||||||
end: DateTime(2017, DateTime.january, 15),
|
end: DateTime(2017, DateTime.january, 15),
|
||||||
@ -393,7 +394,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can switch from calendar to input entry mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can switch from calendar to input entry mode', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNothing);
|
expect(find.byType(TextField), findsNothing);
|
||||||
await tester.tap(find.byIcon(Icons.edit));
|
await tester.tap(find.byIcon(Icons.edit));
|
||||||
@ -402,7 +403,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can switch from input to calendar entry mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can switch from input to calendar entry mode', (WidgetTester tester) async {
|
||||||
initialEntryMode = DatePickerEntryMode.input;
|
initialEntryMode = DatePickerEntryMode.input;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNWidgets(2));
|
expect(find.byType(TextField), findsNWidgets(2));
|
||||||
@ -412,7 +413,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can not switch out of calendarOnly mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can not switch out of calendarOnly mode', (WidgetTester tester) async {
|
||||||
initialEntryMode = DatePickerEntryMode.calendarOnly;
|
initialEntryMode = DatePickerEntryMode.calendarOnly;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNothing);
|
expect(find.byType(TextField), findsNothing);
|
||||||
@ -420,7 +421,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can not switch out of inputOnly mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can not switch out of inputOnly mode', (WidgetTester tester) async {
|
||||||
initialEntryMode = DatePickerEntryMode.inputOnly;
|
initialEntryMode = DatePickerEntryMode.inputOnly;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNWidgets(2));
|
expect(find.byType(TextField), findsNWidgets(2));
|
||||||
@ -428,7 +429,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Input only mode should validate date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Input only mode should validate date', (WidgetTester tester) async {
|
||||||
initialEntryMode = DatePickerEntryMode.inputOnly;
|
initialEntryMode = DatePickerEntryMode.inputOnly;
|
||||||
errorInvalidText = 'oops';
|
errorInvalidText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -442,7 +443,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Switching to input mode keeps selected date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Switching to input mode keeps selected date', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('12').first);
|
await tester.tap(find.text('12').first);
|
||||||
await tester.tap(find.text('14').first);
|
await tester.tap(find.text('14').first);
|
||||||
@ -461,7 +462,7 @@ void main() {
|
|||||||
initialEntryMode = DatePickerEntryMode.input;
|
initialEntryMode = DatePickerEntryMode.input;
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Invalid start date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Invalid start date', (WidgetTester tester) async {
|
||||||
// Invalid start date should have neither a start nor end date selected in
|
// Invalid start date should have neither a start nor end date selected in
|
||||||
// calendar mode
|
// calendar mode
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -475,7 +476,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Invalid end date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Invalid end date', (WidgetTester tester) async {
|
||||||
// Invalid end date should only have a start date selected
|
// Invalid end date should only have a start date selected
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.enterText(find.byType(TextField).at(0), '12/24/2016');
|
await tester.enterText(find.byType(TextField).at(0), '12/24/2016');
|
||||||
@ -488,7 +489,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Invalid range', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Invalid range', (WidgetTester tester) async {
|
||||||
// Start date after end date should just use the start date
|
// Start date after end date should just use the start date
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
||||||
@ -502,7 +503,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('OK Cancel button layout', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('OK Cancel button layout', (WidgetTester tester) async {
|
||||||
Widget buildFrame(TextDirection textDirection) {
|
Widget buildFrame(TextDirection textDirection) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: ThemeData(useMaterial3: false),
|
theme: ThemeData(useMaterial3: false),
|
||||||
@ -577,7 +578,7 @@ void main() {
|
|||||||
feedback.dispose();
|
feedback.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Selecting dates vibrates', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Selecting dates vibrates', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('10').first);
|
await tester.tap(find.text('10').first);
|
||||||
await tester.pump(hapticFeedbackInterval);
|
await tester.pump(hapticFeedbackInterval);
|
||||||
@ -591,7 +592,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Tapping unselectable date does not vibrate', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Tapping unselectable date does not vibrate', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('8').first);
|
await tester.tap(find.text('8').first);
|
||||||
await tester.pump(hapticFeedbackInterval);
|
await tester.pump(hapticFeedbackInterval);
|
||||||
@ -601,7 +602,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('Keyboard navigation', () {
|
group('Keyboard navigation', () {
|
||||||
testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can toggle to calendar entry mode', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNothing);
|
expect(find.byType(TextField), findsNothing);
|
||||||
// Navigate to the entry toggle button and activate it
|
// Navigate to the entry toggle button and activate it
|
||||||
@ -614,7 +615,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can navigate date grid with arrow keys', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
// Navigate to the grid
|
// Navigate to the grid
|
||||||
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
||||||
@ -666,7 +667,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Navigating with arrow keys scrolls as needed', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Navigating with arrow keys scrolls as needed', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
// Jan and Feb headers should be showing, but no March
|
// Jan and Feb headers should be showing, but no March
|
||||||
expect(find.text('January 2016'), findsOneWidget);
|
expect(find.text('January 2016'), findsOneWidget);
|
||||||
@ -731,7 +732,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
// Navigate to the grid
|
// Navigate to the grid
|
||||||
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
||||||
@ -790,7 +791,7 @@ void main() {
|
|||||||
initialEntryMode = DatePickerEntryMode.input;
|
initialEntryMode = DatePickerEntryMode.input;
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Material dialogMaterial = tester.widget<Material>(
|
final Material dialogMaterial = tester.widget<Material>(
|
||||||
@ -813,7 +814,7 @@ void main() {
|
|||||||
}, useMaterial3: theme.useMaterial3);
|
}, useMaterial3: theme.useMaterial3);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default InputDecoration', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default InputDecoration', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final InputDecoration startDateDecoration = tester.widget<TextField>(
|
final InputDecoration startDateDecoration = tester.widget<TextField>(
|
||||||
find.byType(TextField).first).decoration!;
|
find.byType(TextField).first).decoration!;
|
||||||
@ -833,13 +834,13 @@ void main() {
|
|||||||
}, useMaterial3: true);
|
}, useMaterial3: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Initial entry mode is used', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Initial entry mode is used', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNWidgets(2));
|
expect(find.byType(TextField), findsNWidgets(2));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('All custom strings are used', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('All custom strings are used', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
cancelText = 'nope';
|
cancelText = 'nope';
|
||||||
confirmText = 'yep';
|
confirmText = 'yep';
|
||||||
@ -859,7 +860,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Initial date is the default', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.tap(find.text('OK'));
|
await tester.tap(find.text('OK'));
|
||||||
expect(await range, DateTimeRange(
|
expect(await range, DateTimeRange(
|
||||||
@ -869,7 +870,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Can toggle to calendar entry mode', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
expect(find.byType(TextField), findsNWidgets(2));
|
expect(find.byType(TextField), findsNWidgets(2));
|
||||||
await tester.tap(find.byIcon(Icons.calendar_today));
|
await tester.tap(find.byIcon(Icons.calendar_today));
|
||||||
@ -878,7 +879,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Toggle to calendar mode keeps selected date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Toggle to calendar mode keeps selected date', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
||||||
@ -894,7 +895,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Entered text returns range', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Entered text returns range', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
|
||||||
@ -908,7 +909,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Too short entered text shows error', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Too short entered text shows error', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
errorFormatText = 'oops';
|
errorFormatText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -922,7 +923,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Bad format entered text shows error', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Bad format entered text shows error', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
errorFormatText = 'oops';
|
errorFormatText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -936,7 +937,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Invalid entered text shows error', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Invalid entered text shows error', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
errorInvalidText = 'oops';
|
errorInvalidText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -950,7 +951,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('End before start date shows error', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('End before start date shows error', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
errorInvalidRangeText = 'oops';
|
errorInvalidRangeText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -964,7 +965,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Error text only displayed for invalid date', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Error text only displayed for invalid date', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
errorInvalidText = 'oops';
|
errorInvalidText = 'oops';
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -978,7 +979,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('End before start date does not get passed to calendar mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('End before start date does not get passed to calendar mode', (WidgetTester tester) async {
|
||||||
initialDateRange = null;
|
initialDateRange = null;
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
await tester.enterText(find.byType(TextField).at(0), '12/27/2016');
|
await tester.enterText(find.byType(TextField).at(0), '12/27/2016');
|
||||||
@ -996,7 +997,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async {
|
||||||
|
|
||||||
// Given a custom paint for an input decoration, extract the border and
|
// Given a custom paint for an input decoration, extract the border and
|
||||||
// fill color and test them against the expected values.
|
// fill color and test them against the expected values.
|
||||||
@ -1062,7 +1063,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// This is a regression test for https://github.com/flutter/flutter/issues/131989.
|
// This is a regression test for https://github.com/flutter/flutter/issues/131989.
|
||||||
testWidgets('Dialog contents do not overflow when resized from landscape to portrait',
|
testWidgetsWithLeakTracking('Dialog contents do not overflow when resized from landscape to portrait',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
addTearDown(tester.view.reset);
|
addTearDown(tester.view.reset);
|
||||||
// Initial window size is wide for landscape mode.
|
// Initial window size is wide for landscape mode.
|
||||||
@ -1078,7 +1079,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog is state restorable', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DatePickerDialog is state restorable', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
theme: ThemeData(useMaterial3: false),
|
theme: ThemeData(useMaterial3: false),
|
||||||
@ -1134,7 +1135,7 @@ void main() {
|
|||||||
expect(find.text('12/1/2021 to 14/1/2021'), findsOneWidget);
|
expect(find.text('12/1/2021 to 14/1/2021'), findsOneWidget);
|
||||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615
|
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615
|
||||||
|
|
||||||
testWidgets('DateRangePickerDialog state restoration - DatePickerEntryMode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DateRangePickerDialog state restoration - DatePickerEntryMode', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const MaterialApp(
|
const MaterialApp(
|
||||||
restorationScopeId: 'app',
|
restorationScopeId: 'app',
|
||||||
@ -1184,7 +1185,7 @@ void main() {
|
|||||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615
|
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615
|
||||||
|
|
||||||
group('showDateRangePicker avoids overlapping display features', () {
|
group('showDateRangePicker avoids overlapping display features', () {
|
||||||
testWidgets('positioning with anchorPoint', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('positioning with anchorPoint', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
@ -1221,7 +1222,7 @@ void main() {
|
|||||||
expect(tester.getBottomRight(find.byType(DateRangePickerDialog)), const Offset(800.0, 600.0));
|
expect(tester.getBottomRight(find.byType(DateRangePickerDialog)), const Offset(800.0, 600.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('positioning with Directionality', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('positioning with Directionality', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
@ -1261,7 +1262,7 @@ void main() {
|
|||||||
expect(tester.getBottomRight(find.byType(DateRangePickerDialog)), const Offset(800.0, 600.0));
|
expect(tester.getBottomRight(find.byType(DateRangePickerDialog)), const Offset(800.0, 600.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('positioning with defaults', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('positioning with defaults', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
@ -1299,7 +1300,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('Semantics', () {
|
group('Semantics', () {
|
||||||
testWidgets('calendar mode', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('calendar mode', (WidgetTester tester) async {
|
||||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||||
currentDate = DateTime(2016, DateTime.january, 30);
|
currentDate = DateTime(2016, DateTime.january, 30);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
@ -1317,7 +1318,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (final TextInputType? keyboardType in <TextInputType?>[null, TextInputType.emailAddress]) {
|
for (final TextInputType? keyboardType in <TextInputType?>[null, TextInputType.emailAddress]) {
|
||||||
testWidgets('DateRangePicker takes keyboardType $keyboardType', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('DateRangePicker takes keyboardType $keyboardType', (WidgetTester tester) async {
|
||||||
late BuildContext buttonContext;
|
late BuildContext buttonContext;
|
||||||
const InputBorder border = InputBorder.none;
|
const InputBorder border = InputBorder.none;
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(MaterialApp(
|
||||||
@ -1370,7 +1371,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
testWidgets('honors switchToInputEntryModeIcon', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('honors switchToInputEntryModeIcon', (WidgetTester tester) async {
|
||||||
Widget buildApp({bool? useMaterial3, Icon? switchToInputEntryModeIcon}) {
|
Widget buildApp({bool? useMaterial3, Icon? switchToInputEntryModeIcon}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -1425,7 +1426,7 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('honors switchToCalendarEntryModeIcon', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('honors switchToCalendarEntryModeIcon', (WidgetTester tester) async {
|
||||||
Widget buildApp({bool? useMaterial3, Icon? switchToCalendarEntryModeIcon}) {
|
Widget buildApp({bool? useMaterial3, Icon? switchToCalendarEntryModeIcon}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -1488,7 +1489,7 @@ void main() {
|
|||||||
// support is deprecated and the APIs are removed, these tests
|
// support is deprecated and the APIs are removed, these tests
|
||||||
// can be deleted.
|
// can be deleted.
|
||||||
|
|
||||||
testWidgets('Default layout (calendar mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default layout (calendar mode)', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Finder helpText = find.text('SELECT RANGE');
|
final Finder helpText = find.text('SELECT RANGE');
|
||||||
final Finder firstDateHeaderText = find.text('Jan 15');
|
final Finder firstDateHeaderText = find.text('Jan 15');
|
||||||
@ -1544,7 +1545,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default Dialog properties (calendar mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default Dialog properties (calendar mode)', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: false);
|
final ThemeData theme = ThemeData(useMaterial3: false);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Material dialogMaterial = tester.widget<Material>(
|
final Material dialogMaterial = tester.widget<Material>(
|
||||||
@ -1564,7 +1565,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Scaffold and AppBar defaults', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Scaffold and AppBar defaults', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: false);
|
final ThemeData theme = ThemeData(useMaterial3: false);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Scaffold scaffold = tester.widget<Scaffold>(find.byType(Scaffold));
|
final Scaffold scaffold = tester.widget<Scaffold>(find.byType(Scaffold));
|
||||||
@ -1591,7 +1592,7 @@ void main() {
|
|||||||
initialEntryMode = DatePickerEntryMode.input;
|
initialEntryMode = DatePickerEntryMode.input;
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default Dialog properties (input mode)', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: false);
|
final ThemeData theme = ThemeData(useMaterial3: false);
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final Material dialogMaterial = tester.widget<Material>(
|
final Material dialogMaterial = tester.widget<Material>(
|
||||||
@ -1614,7 +1615,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default InputDecoration', (WidgetTester tester) async {
|
testWidgetsWithLeakTracking('Default InputDecoration', (WidgetTester tester) async {
|
||||||
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
await preparePicker(tester, (Future<DateTimeRange?> range) async {
|
||||||
final InputDecoration startDateDecoration = tester.widget<TextField>(
|
final InputDecoration startDateDecoration = tester.widget<TextField>(
|
||||||
find.byType(TextField).first).decoration!;
|
find.byType(TextField).first).decoration!;
|
||||||
@ -1666,6 +1667,14 @@ class _RestorableDateRangePickerDialogTestWidgetState extends State<_RestorableD
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_startDate.dispose();
|
||||||
|
_endDate.dispose();
|
||||||
|
_restorableDateRangePickerRouteFuture.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
|
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
|
||||||
registerForRestoration(_startDate, 'start_date');
|
registerForRestoration(_startDate, 'start_date');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user