[mob][photos] Avoid redundant db calls

This commit is contained in:
laurenspriem 2024-05-13 21:49:02 +05:30
parent ed23286331
commit 2cf193c2d0
2 changed files with 41 additions and 18 deletions

View file

@ -1,5 +1,6 @@
import "dart:async" show StreamSubscription, unawaited;
import "dart:math";
import "dart:typed_data";
import "package:flutter/foundation.dart" show kDebugMode;
import "package:flutter/material.dart";
@ -93,7 +94,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
final bool usingMean = currentSuggestion.usedOnlyMeanForSuggestion;
final List<EnteFile> files = currentSuggestion.filesInCluster;
final Future<bool> generateFaceThumbnails = _generateFaceThumbnails(
final Future<Map<int, Uint8List?>> generateFacedThumbnails = _generateFaceThumbnails(
files.sublist(0, min(files.length, 8)),
clusterID,
);
@ -139,7 +140,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
files,
numberOfDifferentSuggestions,
allSuggestions,
generateFaceThumbnails,
generateFacedThumbnails,
),
),
);
@ -214,7 +215,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
List<EnteFile> files,
int numberOfSuggestions,
List<ClusterSuggestion> allSuggestions,
Future<bool> generateFaceThumbnails,
Future<Map<int, Uint8List?>> generateFaceThumbnails,
) {
final widgetToReturn = Column(
key: ValueKey("cluster_id-$clusterID-files-${files.length}"),
@ -315,15 +316,16 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
Widget _buildThumbnailWidget(
List<EnteFile> files,
int clusterID,
Future<bool> generateFaceThumbnails,
Future<Map<int, Uint8List?>> generateFaceThumbnails,
) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.4,
child: FutureBuilder<bool>(
child: FutureBuilder<Map<int, Uint8List?>>(
key: futureBuilderKeyFaceThumbnails,
future: generateFaceThumbnails,
builder: (context, snapshot) {
if (snapshot.hasData) {
final faceThumbnails = snapshot.data!;
return Column(
children: <Widget>[
Row(
@ -331,6 +333,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
children: _buildThumbnailWidgetsRow(
files,
clusterID,
faceThumbnails,
),
),
if (files.length > 4) const SizedBox(height: 24),
@ -340,6 +343,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
children: _buildThumbnailWidgetsRow(
files,
clusterID,
faceThumbnails,
start: 4,
),
),
@ -363,7 +367,8 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
List<Widget> _buildThumbnailWidgetsRow(
List<EnteFile> files,
int cluserId, {
int cluserId,
Map<int, Uint8List?> faceThumbnails, {
int start = 0,
}) {
return List<Widget>.generate(
@ -379,6 +384,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
clusterID: cluserId,
useFullFile: false,
thumbnailFallback: false,
faceCrop: faceThumbnails[files[start + index].uploadedFileID!],
),
),
),
@ -386,11 +392,11 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
);
}
Future<bool> _generateFaceThumbnails(
Future<Map<int, Uint8List?>> _generateFaceThumbnails(
List<EnteFile> files,
int clusterID,
) async {
final futures = <Future<void>>[];
final futures = <Future<Uint8List?>>[];
for (final file in files) {
futures.add(
PersonFaceWidget.precomputeNextFaceCrops(
@ -400,7 +406,11 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
),
);
}
await Future.wait(futures);
return true;
final faceCropsList = await Future.wait(futures);
final faceCrops = <int, Uint8List?>{};
for (var i = 0; i < faceCropsList.length; i++) {
faceCrops[files[i].uploadedFileID!] = faceCropsList[i];
}
return faceCrops;
}
}

View file

@ -22,6 +22,7 @@ class PersonFaceWidget extends StatelessWidget {
final int? clusterID;
final bool useFullFile;
final bool thumbnailFallback;
final Uint8List? faceCrop;
// PersonFaceWidget constructor checks that both personId and clusterID are not null
// and that the file is not null
@ -31,6 +32,7 @@ class PersonFaceWidget extends StatelessWidget {
this.clusterID,
this.useFullFile = true,
this.thumbnailFallback = true,
this.faceCrop,
Key? key,
}) : assert(
personId != null || clusterID != null,
@ -40,6 +42,17 @@ class PersonFaceWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (faceCrop != null) {
return Stack(
fit: StackFit.expand,
children: [
Image(
image: MemoryImage(faceCrop!),
fit: BoxFit.cover,
),
],
);
}
if (useGeneratedFaceCrops) {
return FutureBuilder<Uint8List?>(
future: getFaceCrop(),
@ -171,7 +184,7 @@ class PersonFaceWidget extends StatelessWidget {
}
}
static Future<void> precomputeNextFaceCrops(
static Future<Uint8List?> precomputeNextFaceCrops(
file,
clusterID, {
required bool useFullFile,
@ -185,23 +198,23 @@ class PersonFaceWidget extends StatelessWidget {
debugPrint(
"No cover face for cluster $clusterID and recentFile ${file.uploadedFileID}",
);
return;
return null;
}
final Uint8List? cachedFace = faceCropCache.get(face.faceID);
if (cachedFace != null) {
return;
return cachedFace;
}
final faceCropCacheFile = cachedFaceCropPath(face.faceID);
if ((await faceCropCacheFile.exists())) {
final data = await faceCropCacheFile.readAsBytes();
faceCropCache.put(face.faceID, data);
return;
return data;
}
if (!useFullFile) {
final Uint8List? cachedFaceThumbnail =
faceCropThumbnailCache.get(face.faceID);
if (cachedFaceThumbnail != null) {
return;
return cachedFaceThumbnail;
}
}
EnteFile? fileForFaceCrop = file;
@ -210,7 +223,7 @@ class PersonFaceWidget extends StatelessWidget {
await FilesDB.instance.getAnyUploadedFile(face.fileID);
}
if (fileForFaceCrop == null) {
return;
return null;
}
final result = await pool.withResource(
@ -231,14 +244,14 @@ class PersonFaceWidget extends StatelessWidget {
faceCropThumbnailCache.put(face.faceID, computedCrop);
}
}
return;
return computedCrop;
} catch (e, s) {
log(
"Error getting cover face for cluster $clusterID",
error: e,
stackTrace: s,
);
return;
return null;
}
}
}