[mob][photos] Avoid redundant db calls
This commit is contained in:
parent
ed23286331
commit
2cf193c2d0
2 changed files with 41 additions and 18 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue