Unverified Commit d76e3abf authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

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`.
parent 670e6ba1
...@@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart'; ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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(
testWidgets('Dividers use DatePickerThemeData.dividerColor', (WidgetTester tester) async { // TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/136036
notDisposedAllowList: <String, int?> {'AnnotatedRegionLayer<SystemUiOverlayStyle>': 2},
));
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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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},
));
} }
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