[mob][photos] Small refactor
This commit is contained in:
parent
1f82599fb6
commit
d7e7aaa26f
|
@ -54,233 +54,24 @@ class _FaceWidgetState extends State<FaceWidget> {
|
|||
Widget build(BuildContext context) {
|
||||
final bool givenFaces = widget.faceCrops != null;
|
||||
if (useGeneratedFaceCrops) {
|
||||
return FutureBuilder<Map<String, Uint8List>?>(
|
||||
future: givenFaces ? widget.faceCrops : getFaceCrop(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final ImageProvider imageProvider =
|
||||
MemoryImage(snapshot.data![widget.face.faceID]!);
|
||||
|
||||
return GestureDetector(
|
||||
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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
return _buildFaceImageGenerated(givenFaces);
|
||||
} else {
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
return _buildFaceImageFlutterZoom();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildFaceImageGenerated(bool givenFaces) {
|
||||
return FutureBuilder<Map<String, Uint8List>?>(
|
||||
future: givenFaces ? widget.faceCrops : getFaceCrop(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final ImageProvider imageProvider =
|
||||
MemoryImage(snapshot.data![widget.face.faceID]!);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
if (widget.editMode) return;
|
||||
|
||||
log(
|
||||
"FaceWidget is tapped, with person ${widget.person} and clusterID ${widget.clusterID}",
|
||||
name: "FaceWidget",
|
||||
|
@ -386,9 +177,9 @@ class _FaceWidgetState extends State<FaceWidget> {
|
|||
child: SizedBox(
|
||||
width: 60,
|
||||
height: 60,
|
||||
child: CroppedFaceImageView(
|
||||
enteFile: widget.file,
|
||||
face: widget.face,
|
||||
child: Image(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -416,7 +207,9 @@ class _FaceWidgetState extends State<FaceWidget> {
|
|||
const SizedBox(height: 8),
|
||||
if (widget.person != null)
|
||||
Text(
|
||||
widget.person!.data.name.trim(),
|
||||
widget.person!.data.isIgnored
|
||||
? '(ignored)'
|
||||
: widget.person!.data.name.trim(),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
|
@ -445,12 +238,40 @@ class _FaceWidgetState extends State<FaceWidget> {
|
|||
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 {
|
||||
|
@ -508,4 +329,178 @@ class _FaceWidgetState extends State<FaceWidget> {
|
|||
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(
|
||||
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: CroppedFaceImageView(
|
||||
enteFile: widget.file,
|
||||
face: widget.face,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
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.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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue