[mob][photos] Small refactor

This commit is contained in:
laurenspriem 2024-05-17 10:32:37 +05:30
parent 1f82599fb6
commit d7e7aaa26f

View file

@ -54,6 +54,13 @@ class _FaceWidgetState extends State<FaceWidget> {
Widget build(BuildContext context) {
final bool givenFaces = widget.faceCrops != null;
if (useGeneratedFaceCrops) {
return _buildFaceImageGenerated(givenFaces);
} else {
return _buildFaceImageFlutterZoom();
}
}
Widget _buildFaceImageGenerated(bool givenFaces) {
return FutureBuilder<Map<String, Uint8List>?>(
future: givenFaces ? widget.faceCrops : getFaceCrop(),
builder: (context, snapshot) {
@ -65,222 +72,6 @@ class _FaceWidgetState extends State<FaceWidget> {
onTap: () async {
if (widget.editMode) return;
log(
"FaceWidget is tapped, with person ${widget.person} and clusterID ${widget.clusterID}",
name: "FaceWidget",
);
if (widget.person == null && widget.clusterID == null) {
// Get faceID and double check that it doesn't belong to an existing clusterID. If it does, push that cluster page
final w = (kDebugMode ? EnteWatch('FaceWidget') : null)
?..start();
final existingClusterID = await FaceMLDataDB.instance
.getClusterIDForFaceID(widget.face.faceID);
w?.log('getting existing clusterID for faceID');
if (existingClusterID != null) {
final fileIdsToClusterIds =
await FaceMLDataDB.instance.getFileIdToClusterIds();
final files = await SearchService.instance.getAllFiles();
final clusterFiles = files
.where(
(file) =>
fileIdsToClusterIds[file.uploadedFileID]
?.contains(existingClusterID) ??
false,
)
.toList();
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
clusterFiles,
clusterID: existingClusterID,
),
),
);
}
// Create new clusterID for the faceID and update DB to assign the faceID to the new clusterID
final int newClusterID =
DateTime.now().microsecondsSinceEpoch;
await FaceMLDataDB.instance.updateFaceIdToClusterId(
{widget.face.faceID: newClusterID},
);
// Push page for the new cluster
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
[widget.file],
clusterID: newClusterID,
),
),
);
}
if (widget.person != null) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PeoplePage(
person: widget.person!,
),
),
);
} else if (widget.clusterID != null) {
final fileIdsToClusterIds =
await FaceMLDataDB.instance.getFileIdToClusterIds();
final files = await SearchService.instance.getAllFiles();
final clusterFiles = files
.where(
(file) =>
fileIdsToClusterIds[file.uploadedFileID]
?.contains(widget.clusterID) ??
false,
)
.toList();
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
clusterFiles,
clusterID: widget.clusterID!,
),
),
);
}
},
child: Column(
children: [
Stack(
children: [
Container(
height: 60,
width: 60,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(
Radius.elliptical(16, 12),
),
side: widget.highlight
? BorderSide(
color:
getEnteColorScheme(context).primary700,
width: 1.0,
)
: BorderSide.none,
),
),
child: ClipRRect(
borderRadius:
const BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60,
height: 60,
child: Image(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
),
// TODO: the edges of the green line are still not properly rounded around ClipRRect
if (widget.editMode)
Positioned(
right: 0,
top: 0,
child: GestureDetector(
onTap: _cornerIconPressed,
child: isJustRemoved
? const Icon(
CupertinoIcons.add_circled_solid,
color: Colors.green,
)
: const Icon(
Icons.cancel,
color: Colors.red,
),
),
),
],
),
const SizedBox(height: 8),
if (widget.person != null)
Text(
widget.person!.data.isIgnored
? '(ignored)'
: widget.person!.data.name.trim(),
style: Theme.of(context).textTheme.bodySmall,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
if (kDebugMode)
Text(
'S: ${widget.face.score.toStringAsFixed(3)}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'B: ${widget.face.blur.toStringAsFixed(0)}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'D: ${widget.face.detection.getFaceDirection().toDirectionString()}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'Sideways: ${widget.face.detection.faceIsSideways().toString()}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode && widget.face.score < 0.75)
Text(
'[Debug only]',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
// if (kDebugMode)
// if (highlight)
// const Text(
// "Highlighted",
// style: TextStyle(
// color: Colors.red,
// fontSize: 12,
// ),
// ),
],
),
);
} else {
if (snapshot.connectionState == ConnectionState.waiting) {
return const ClipRRect(
borderRadius: BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60, // Ensure consistent sizing
height: 60,
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
log('Error getting face: ${snapshot.error}');
}
return const ClipRRect(
borderRadius: BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60, // Ensure consistent sizing
height: 60,
child: NoThumbnailWidget(),
),
);
}
},
);
} else {
return Builder(
builder: (context) {
return GestureDetector(
onTap: () async {
log(
"FaceWidget is tapped, with person ${widget.person} and clusterID ${widget.clusterID}",
name: "FaceWidget",
@ -360,6 +151,268 @@ class _FaceWidgetState extends State<FaceWidget> {
);
}
},
child: Column(
children: [
Stack(
children: [
Container(
height: 60,
width: 60,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(
Radius.elliptical(16, 12),
),
side: widget.highlight
? BorderSide(
color: getEnteColorScheme(context).primary700,
width: 1.0,
)
: BorderSide.none,
),
),
child: ClipRRect(
borderRadius:
const BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60,
height: 60,
child: Image(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
),
// TODO: the edges of the green line are still not properly rounded around ClipRRect
if (widget.editMode)
Positioned(
right: 0,
top: 0,
child: GestureDetector(
onTap: _cornerIconPressed,
child: isJustRemoved
? const Icon(
CupertinoIcons.add_circled_solid,
color: Colors.green,
)
: const Icon(
Icons.cancel,
color: Colors.red,
),
),
),
],
),
const SizedBox(height: 8),
if (widget.person != null)
Text(
widget.person!.data.isIgnored
? '(ignored)'
: widget.person!.data.name.trim(),
style: Theme.of(context).textTheme.bodySmall,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
if (kDebugMode)
Text(
'S: ${widget.face.score.toStringAsFixed(3)}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'B: ${widget.face.blur.toStringAsFixed(0)}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'D: ${widget.face.detection.getFaceDirection().toDirectionString()}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode)
Text(
'Sideways: ${widget.face.detection.faceIsSideways().toString()}',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
if (kDebugMode && widget.face.score < 0.75)
Text(
'[Debug only]',
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
],
),
);
} else {
if (snapshot.connectionState == ConnectionState.waiting) {
return const ClipRRect(
borderRadius: BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
log('Error getting face: ${snapshot.error}');
}
return const ClipRRect(
borderRadius: BorderRadius.all(Radius.elliptical(16, 12)),
child: SizedBox(
width: 60,
height: 60,
child: NoThumbnailWidget(),
),
);
}
},
);
}
void _cornerIconPressed() async {
log('face widget (file info) corner icon is pressed');
try {
if (isJustRemoved) {
await ClusterFeedbackService.instance
.addFilesToCluster([widget.face.faceID], widget.clusterID!);
} else {
await ClusterFeedbackService.instance
.removeFilesFromCluster([widget.file], widget.clusterID!);
}
setState(() {
isJustRemoved = !isJustRemoved;
});
} catch (e, s) {
log("removing face/file from cluster from file info widget failed: $e, \n $s");
}
}
Future<Map<String, Uint8List>?> getFaceCrop() async {
try {
final Uint8List? cachedFace = faceCropCache.get(widget.face.faceID);
if (cachedFace != null) {
return {widget.face.faceID: cachedFace};
}
final faceCropCacheFile = cachedFaceCropPath(widget.face.faceID);
if ((await faceCropCacheFile.exists())) {
final data = await faceCropCacheFile.readAsBytes();
faceCropCache.put(widget.face.faceID, data);
return {widget.face.faceID: data};
}
final result = await pool.withResource(
() async => await getFaceCrops(
widget.file,
{
widget.face.faceID: widget.face.detection.box,
},
),
);
final Uint8List? computedCrop = result?[widget.face.faceID];
if (computedCrop != null) {
faceCropCache.put(widget.face.faceID, computedCrop);
faceCropCacheFile.writeAsBytes(computedCrop).ignore();
}
return {widget.face.faceID: computedCrop!};
} catch (e, s) {
log(
"Error getting face for faceID: ${widget.face.faceID}",
error: e,
stackTrace: s,
);
return null;
}
}
Widget _buildFaceImageFlutterZoom() {
return Builder(
builder: (context) {
return GestureDetector(
onTap: () async {
log(
"FaceWidget is tapped, with person ${widget.person} and clusterID ${widget.clusterID}",
name: "FaceWidget",
);
if (widget.person == null && widget.clusterID == null) {
// Get faceID and double check that it doesn't belong to an existing clusterID. If it does, push that cluster page
final w = (kDebugMode ? EnteWatch('FaceWidget') : null)?..start();
final existingClusterID = await FaceMLDataDB.instance
.getClusterIDForFaceID(widget.face.faceID);
w?.log('getting existing clusterID for faceID');
if (existingClusterID != null) {
final fileIdsToClusterIds =
await FaceMLDataDB.instance.getFileIdToClusterIds();
final files = await SearchService.instance.getAllFiles();
final clusterFiles = files
.where(
(file) =>
fileIdsToClusterIds[file.uploadedFileID]
?.contains(existingClusterID) ??
false,
)
.toList();
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
clusterFiles,
clusterID: existingClusterID,
),
),
);
}
// Create new clusterID for the faceID and update DB to assign the faceID to the new clusterID
final int newClusterID = DateTime.now().microsecondsSinceEpoch;
await FaceMLDataDB.instance.updateFaceIdToClusterId(
{widget.face.faceID: newClusterID},
);
// Push page for the new cluster
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
[widget.file],
clusterID: newClusterID,
),
),
);
}
if (widget.person != null) {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PeoplePage(
person: widget.person!,
),
),
);
} else if (widget.clusterID != null) {
final fileIdsToClusterIds =
await FaceMLDataDB.instance.getFileIdToClusterIds();
final files = await SearchService.instance.getAllFiles();
final clusterFiles = files
.where(
(file) =>
fileIdsToClusterIds[file.uploadedFileID]
?.contains(widget.clusterID) ??
false,
)
.toList();
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ClusterPage(
clusterFiles,
clusterID: widget.clusterID!,
),
),
);
}
},
child: Column(
children: [
Stack(
@ -393,7 +446,6 @@ class _FaceWidgetState extends State<FaceWidget> {
),
),
),
// TODO: the edges of the green line are still not properly rounded around ClipRRect
if (widget.editMode)
Positioned(
right: 0,
@ -452,60 +504,3 @@ class _FaceWidgetState extends State<FaceWidget> {
);
}
}
void _cornerIconPressed() async {
log('face widget (file info) corner icon is pressed');
try {
if (isJustRemoved) {
await ClusterFeedbackService.instance
.addFilesToCluster([widget.face.faceID], widget.clusterID!);
} else {
await ClusterFeedbackService.instance
.removeFilesFromCluster([widget.file], widget.clusterID!);
}
setState(() {
isJustRemoved = !isJustRemoved;
});
} catch (e, s) {
log("removing face/file from cluster from file info widget failed: $e, \n $s");
}
}
Future<Map<String, Uint8List>?> getFaceCrop() async {
try {
final Uint8List? cachedFace = faceCropCache.get(widget.face.faceID);
if (cachedFace != null) {
return {widget.face.faceID: cachedFace};
}
final faceCropCacheFile = cachedFaceCropPath(widget.face.faceID);
if ((await faceCropCacheFile.exists())) {
final data = await faceCropCacheFile.readAsBytes();
faceCropCache.put(widget.face.faceID, data);
return {widget.face.faceID: data};
}
final result = await pool.withResource(
() async => await getFaceCrops(
widget.file,
{
widget.face.faceID: widget.face.detection.box,
},
),
);
final Uint8List? computedCrop = result?[widget.face.faceID];
if (computedCrop != null) {
faceCropCache.put(widget.face.faceID, computedCrop);
faceCropCacheFile.writeAsBytes(computedCrop).ignore();
}
return {widget.face.faceID: computedCrop!};
} catch (e, s) {
log(
"Error getting face for faceID: ${widget.face.faceID}",
error: e,
stackTrace: s,
);
return null;
}
}
}