diff --git a/lib/model/query.dart b/lib/model/query.dart index 79d63e47a..518d6941f 100644 --- a/lib/model/query.dart +++ b/lib/model/query.dart @@ -19,6 +19,7 @@ class Query extends ChangeNotifier { @override void dispose() { _focusRequestNotifier.dispose(); + _queryNotifier.dispose(); super.dispose(); } diff --git a/lib/model/source/collection_lens.dart b/lib/model/source/collection_lens.dart index b765c9f58..747e3bd1e 100644 --- a/lib/model/source/collection_lens.dart +++ b/lib/model/source/collection_lens.dart @@ -37,6 +37,7 @@ class CollectionLens with ChangeNotifier { bool listenToSource, groupBursts, fixedSort; List? fixedSelection; + final Set _syntheticEntries = {}; List _filteredSortedEntries = []; Map> sections = Map.unmodifiable({}); @@ -101,6 +102,7 @@ class CollectionLens with ChangeNotifier { favourites.removeListener(_onFavouritesChanged); filterChangeNotifier.dispose(); sortSectionChangeNotifier.dispose(); + _disposeSyntheticEntries(); super.dispose(); } @@ -118,6 +120,11 @@ class CollectionLens with ChangeNotifier { fixedSelection: fixedSelection ?? this.fixedSelection, ); + void _disposeSyntheticEntries() { + _syntheticEntries.forEach((v) => v.dispose()); + _syntheticEntries.clear(); + } + bool get isEmpty => _filteredSortedEntries.isEmpty; int get entryCount => _filteredSortedEntries.length; @@ -182,6 +189,7 @@ class CollectionLens with ChangeNotifier { void _applyFilters() { final entries = fixedSelection ?? (filters.contains(TrashFilter.instance) ? source.trashedEntries : source.visibleEntries); + _disposeSyntheticEntries(); _filteredSortedEntries = List.of(filters.isEmpty ? entries : entries.where((entry) => filters.every((filter) => filter.test(entry)))); if (groupBursts) { @@ -196,6 +204,7 @@ class CollectionLens with ChangeNotifier { entries.sort(AvesEntrySort.compareByName); final mainEntry = entries.first; final burstEntry = mainEntry.copyWith(burstEntries: entries); + _syntheticEntries.add(burstEntry); entries.skip(1).toList().forEach((subEntry) { _filteredSortedEntries.remove(subEntry); diff --git a/lib/widgets/common/basic/query_bar.dart b/lib/widgets/common/basic/query_bar.dart index 24dd2637b..08203b60a 100644 --- a/lib/widgets/common/basic/query_bar.dart +++ b/lib/widgets/common/basic/query_bar.dart @@ -41,6 +41,12 @@ class _QueryBarState extends State { _controller = TextEditingController(text: queryNotifier.value); } + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final clearButton = IconButton( diff --git a/lib/widgets/common/grid/scaling.dart b/lib/widgets/common/grid/scaling.dart index 5a68ec6e0..c05b3f63e 100644 --- a/lib/widgets/common/grid/scaling.dart +++ b/lib/widgets/common/grid/scaling.dart @@ -55,6 +55,12 @@ class _GridScaleGestureDetectorState extends State widget.tileLayout; + @override + void dispose() { + _scaledSizeNotifier?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final gestureSettings = MediaQuery.gestureSettingsOf(context); @@ -166,6 +172,7 @@ class _GridScaleGestureDetectorState extends State extends State extends State currentBodyNotifier = ValueNotifier(null); AvesSearchDelegate({ required this.routeName, @@ -31,6 +33,8 @@ abstract class AvesSearchDelegate extends SearchDelegate { if (kFlutterMemoryAllocationsEnabled) { MemoryAllocations.instance.dispatchObjectDisposed(object: this); } + queryTextController.dispose(); + currentBodyNotifier.dispose(); } @override @@ -113,8 +117,6 @@ abstract class AvesSearchDelegate extends SearchDelegate { ScrollController? get suggestionsScrollController => null; - final TextEditingController queryTextController = TextEditingController(); - final ProxyAnimation proxyAnimation = ProxyAnimation(kAlwaysDismissedAnimation); @override @@ -128,8 +130,6 @@ abstract class AvesSearchDelegate extends SearchDelegate { } } - final ValueNotifier currentBodyNotifier = ValueNotifier(null); - SearchBody? get currentBody => currentBodyNotifier.value; set currentBody(SearchBody? value) { diff --git a/lib/widgets/debug/android_apps.dart b/lib/widgets/debug/android_apps.dart index b7f42041c..708566eda 100644 --- a/lib/widgets/debug/android_apps.dart +++ b/lib/widgets/debug/android_apps.dart @@ -26,6 +26,12 @@ class _DebugAndroidAppSectionState extends State with Au _loader = appService.getPackages(); } + @override + void dispose() { + _queryNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/widgets/debug/android_codecs.dart b/lib/widgets/debug/android_codecs.dart index 054e4a7d3..dfdfe169a 100644 --- a/lib/widgets/debug/android_codecs.dart +++ b/lib/widgets/debug/android_codecs.dart @@ -23,6 +23,12 @@ class _DebugAndroidCodecSectionState extends State wit _loader = AndroidDebugService.getCodecs(); } + @override + void dispose() { + _queryNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/widgets/debug/general.dart b/lib/widgets/debug/general.dart index 0cfd32ae4..a85913b0b 100644 --- a/lib/widgets/debug/general.dart +++ b/lib/widgets/debug/general.dart @@ -71,9 +71,15 @@ class _DebugGeneralSectionState extends State with Automati debugPrint(' * report type=$reportType'); groupBy(typedReports, (report) => report.trackedClass).forEach((trackedClass, classedReports) { debugPrint(' trackedClass=$trackedClass reports=${classedReports.length}'); - // classedReports.forEach((report) { - // debugPrint(' phase=${report.phase} retainingPath=${report.retainingPath} detailedPath=${report.detailedPath} context=${report.context}'); - // }); + classedReports.forEach((report) { + final phase = report.phase; + final retainingPath = report.retainingPath; + final detailedPath = report.detailedPath; + final context = report.context; + if (phase != null || retainingPath != null || detailedPath != null || context != null) { + debugPrint(' phase=$phase retainingPath=$retainingPath detailedPath=$detailedPath context=$context'); + } + }); }); }); }); diff --git a/lib/widgets/dialogs/entry_editors/edit_description_dialog.dart b/lib/widgets/dialogs/entry_editors/edit_description_dialog.dart index 239885316..60c77b9e2 100644 --- a/lib/widgets/dialogs/entry_editors/edit_description_dialog.dart +++ b/lib/widgets/dialogs/entry_editors/edit_description_dialog.dart @@ -34,6 +34,13 @@ class _EditEntryTitleDescriptionDialogState extends State { @override void dispose() { - _patternTextController.removeListener(_onUserPatternChanged); + _patternTextController.dispose(); + _namingPatternNotifier.dispose(); super.dispose(); } diff --git a/lib/widgets/dialogs/entry_editors/tag_editor_page.dart b/lib/widgets/dialogs/entry_editors/tag_editor_page.dart index 885bf0fba..2c280f807 100644 --- a/lib/widgets/dialogs/entry_editors/tag_editor_page.dart +++ b/lib/widgets/dialogs/entry_editors/tag_editor_page.dart @@ -54,6 +54,7 @@ class _TagEditorPageState extends State { @override void dispose() { + _newTagTextController.dispose(); _newTagTextFocusNode.dispose(); _expandedSectionNotifier.dispose(); super.dispose(); diff --git a/lib/widgets/dialogs/filter_editors/create_album_dialog.dart b/lib/widgets/dialogs/filter_editors/create_album_dialog.dart index 20bb2a2ea..9943eab7c 100644 --- a/lib/widgets/dialogs/filter_editors/create_album_dialog.dart +++ b/lib/widgets/dialogs/filter_editors/create_album_dialog.dart @@ -39,6 +39,7 @@ class _CreateAlbumDialogState extends State { @override void dispose() { + _scrollController.dispose(); _nameController.dispose(); _nameFieldFocusNode.removeListener(_onFocus); _nameFieldFocusNode.dispose(); diff --git a/lib/widgets/dialogs/filter_editors/password_dialog.dart b/lib/widgets/dialogs/filter_editors/password_dialog.dart index 08f4864e8..72f633131 100644 --- a/lib/widgets/dialogs/filter_editors/password_dialog.dart +++ b/lib/widgets/dialogs/filter_editors/password_dialog.dart @@ -28,6 +28,13 @@ class _PasswordDialogState extends State { _focusNode.requestFocus(); } + @override + void dispose() { + _controller.dispose(); + _focusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return AvesDialog( diff --git a/lib/widgets/dialogs/filter_editors/pin_dialog.dart b/lib/widgets/dialogs/filter_editors/pin_dialog.dart index 52098c5b7..9bfdcc0cc 100644 --- a/lib/widgets/dialogs/filter_editors/pin_dialog.dart +++ b/lib/widgets/dialogs/filter_editors/pin_dialog.dart @@ -22,6 +22,12 @@ class _PinDialogState extends State { bool _confirming = false; String? _firstPin; + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; diff --git a/lib/widgets/dialogs/pick_dialogs/app_pick_page.dart b/lib/widgets/dialogs/pick_dialogs/app_pick_page.dart index 997388968..f38d386a9 100644 --- a/lib/widgets/dialogs/pick_dialogs/app_pick_page.dart +++ b/lib/widgets/dialogs/pick_dialogs/app_pick_page.dart @@ -37,6 +37,12 @@ class _AppPickPageState extends State { _loader = appService.getPackages(); } + @override + void dispose() { + _queryNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final useTvLayout = settings.useTvLayout; diff --git a/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart b/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart index 6ceb180c1..310c6d821 100644 --- a/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart +++ b/lib/widgets/dialogs/pick_dialogs/location_pick_page.dart @@ -253,6 +253,12 @@ class _AddressRowState extends State<_AddressRow> { } } + @override + void dispose() { + _addressLineNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final textScaleFactor = MediaQuery.textScaleFactorOf(context); diff --git a/lib/widgets/home_widget.dart b/lib/widgets/home_widget.dart index f01bce2ce..62f106af3 100644 --- a/lib/widgets/home_widget.dart +++ b/lib/widgets/home_widget.dart @@ -33,7 +33,7 @@ class HomeWidgetPainter { ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba, }) async { final widgetSizePx = Size(widthPx.toDouble(), heightPx.toDouble()); - late final ui.Image? entryImage; + final ui.Image? entryImage; if (entry != null) { final extent = shape.extentPx(widgetSizePx, entry!) / devicePixelRatio; entryImage = await _getEntryImage(entry, extent); @@ -48,6 +48,7 @@ class HomeWidgetPainter { canvas.clipPath(path); if (entryImage != null) { canvas.drawImage(entryImage, Offset(widgetSizePx.width - entryImage.width, widgetSizePx.height - entryImage.height) / 2, Paint()); + entryImage.dispose(); } else { canvas.drawPaint(Paint()..shader = backgroundGradient.createShader(rect)); } diff --git a/lib/widgets/map/address_row.dart b/lib/widgets/map/address_row.dart index daeab20ed..2bdfdfc42 100644 --- a/lib/widgets/map/address_row.dart +++ b/lib/widgets/map/address_row.dart @@ -41,6 +41,12 @@ class _MapAddressRowState extends State { } } + @override + void dispose() { + _addressLineNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final textScaleFactor = MediaQuery.textScaleFactorOf(context); diff --git a/lib/widgets/settings/language/locale_selection_page.dart b/lib/widgets/settings/language/locale_selection_page.dart index b1d02fe13..1612e70cf 100644 --- a/lib/widgets/settings/language/locale_selection_page.dart +++ b/lib/widgets/settings/language/locale_selection_page.dart @@ -29,6 +29,12 @@ class _LocaleSelectionPageState extends State { _selectedValue = settings.locale ?? LocaleTile.systemLocaleOption; } + @override + void dispose() { + _queryNotifier.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final useTvLayout = settings.useTvLayout; diff --git a/lib/widgets/viewer/info/metadata/metadata_section.dart b/lib/widgets/viewer/info/metadata/metadata_section.dart index c040b20b4..42ba3ccb6 100644 --- a/lib/widgets/viewer/info/metadata/metadata_section.dart +++ b/lib/widgets/viewer/info/metadata/metadata_section.dart @@ -55,6 +55,7 @@ class _MetadataSectionSliverState extends State { @override void dispose() { _unregisterWidget(widget); + _expandedDirectoryNotifier.dispose(); super.dispose(); } diff --git a/plugins/aves_services_google/lib/src/map.dart b/plugins/aves_services_google/lib/src/map.dart index d78377e4f..10887217e 100644 --- a/plugins/aves_services_google/lib/src/map.dart +++ b/plugins/aves_services_google/lib/src/map.dart @@ -87,7 +87,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi _unregisterWidget(widget); _serviceMapController?.dispose(); WidgetsBinding.instance.removeObserver(this); - _sizeNotifier.removeListener(_onSizeChange); + _sizeNotifier.dispose(); super.dispose(); }