From c2d1c668887ec5baca472d00f520c2cce24387ba Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Wed, 23 Jul 2025 12:45:09 +0200 Subject: [PATCH] keep alive face thumbnail when scrolling fast --- .../ui/viewer/people/person_face_widget.dart | 12 +++++++++++- .../search/result/people_section_all_page.dart | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/mobile/apps/photos/lib/ui/viewer/people/person_face_widget.dart b/mobile/apps/photos/lib/ui/viewer/people/person_face_widget.dart index 0327c5853d..3e1b138c26 100644 --- a/mobile/apps/photos/lib/ui/viewer/people/person_face_widget.dart +++ b/mobile/apps/photos/lib/ui/viewer/people/person_face_widget.dart @@ -21,6 +21,7 @@ class PersonFaceWidget extends StatefulWidget { final String? clusterID; final bool useFullFile; final VoidCallback? onErrorCallback; + final bool keepAlive; // PersonFaceWidget constructor checks that both personId and clusterID are not null // and that the file is not null @@ -29,6 +30,7 @@ class PersonFaceWidget extends StatefulWidget { this.clusterID, this.useFullFile = true, this.onErrorCallback, + this.keepAlive = false, super.key, }) : assert( personId != null || clusterID != null, @@ -39,12 +41,16 @@ class PersonFaceWidget extends StatefulWidget { State createState() => _PersonFaceWidgetState(); } -class _PersonFaceWidgetState extends State { +class _PersonFaceWidgetState extends State + with AutomaticKeepAliveClientMixin { Future? faceCropFuture; EnteFile? fileForFaceCrop; bool get isPerson => widget.personId != null; + @override + bool get wantKeepAlive => widget.keepAlive; + @override void initState() { super.initState(); @@ -64,6 +70,10 @@ class _PersonFaceWidgetState extends State { @override Widget build(BuildContext context) { + super.build( + context, + ); // Calling super.build for AutomaticKeepAliveClientMixin + return FutureBuilder( future: faceCropFuture, builder: (context, snapshot) { diff --git a/mobile/apps/photos/lib/ui/viewer/search/result/people_section_all_page.dart b/mobile/apps/photos/lib/ui/viewer/search/result/people_section_all_page.dart index d78eb4b9ba..d711bd9ebd 100644 --- a/mobile/apps/photos/lib/ui/viewer/search/result/people_section_all_page.dart +++ b/mobile/apps/photos/lib/ui/viewer/search/result/people_section_all_page.dart @@ -95,12 +95,14 @@ class SelectablePersonSearchExample extends StatelessWidget { final GenericSearchResult searchResult; final double size; final SelectedPeople selectedPeople; + final bool isDefaultFace; const SelectablePersonSearchExample({ super.key, required this.searchResult, required this.selectedPeople, this.size = 102, + this.isDefaultFace = false, }); void _handleTap(BuildContext context) { @@ -192,7 +194,10 @@ class SelectablePersonSearchExample extends StatelessWidget { searchResult.previewThumbnail()!, shouldShowSyncStatus: false, ) - : FaceSearchResult(searchResult); + : FaceSearchResult( + searchResult, + isDefaultFace: isDefaultFace, + ); } else { child = const NoThumbnailWidget( addBorder: false, @@ -301,8 +306,13 @@ class SelectablePersonSearchExample extends StatelessWidget { class FaceSearchResult extends StatelessWidget { final SearchResult searchResult; + final bool isDefaultFace; - const FaceSearchResult(this.searchResult, {super.key}); + const FaceSearchResult( + this.searchResult, { + super.key, + this.isDefaultFace = false, + }); @override Widget build(BuildContext context) { @@ -313,6 +323,7 @@ class FaceSearchResult extends StatelessWidget { key: params.containsKey(kPersonWidgetKey) ? ValueKey(params[kPersonWidgetKey]) : ValueKey(params[kPersonParamID] ?? params[kClusterParamId]), + keepAlive: isDefaultFace, ); } } @@ -486,6 +497,7 @@ class _PeopleSectionAllWidgetState extends State { searchResult: normalFaces[index], size: itemSize, selectedPeople: widget.selectedPeople!, + isDefaultFace: true, ) : PersonSearchExample( searchResult: normalFaces[index], @@ -525,6 +537,7 @@ class _PeopleSectionAllWidgetState extends State { searchResult: extraFaces[index], size: itemSize, selectedPeople: widget.selectedPeople!, + isDefaultFace: false, ) : PersonSearchExample( searchResult: extraFaces[index],