[mob] Rename and add more attr to PersonEntity

This commit is contained in:
Neeraj Gupta 2024-04-04 16:06:16 +05:30
parent 2163201046
commit f5a9679c0e
24 changed files with 159 additions and 98 deletions

View file

@ -154,6 +154,8 @@ PODS:
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.1.1):
- Flutter
- photo_manager (2.0.0): - photo_manager (2.0.0):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -272,6 +274,7 @@ DEPENDENCIES:
- open_mail_app (from `.symlinks/plugins/open_mail_app/ios`) - open_mail_app (from `.symlinks/plugins/open_mail_app/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`) - photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`) - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
@ -383,6 +386,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
photo_manager: photo_manager:
:path: ".symlinks/plugins/photo_manager/ios" :path: ".symlinks/plugins/photo_manager/ios"
receive_sharing_intent: receive_sharing_intent:
@ -462,6 +467,7 @@ SPEC CHECKSUMS:
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604 photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825

View file

@ -226,8 +226,8 @@ class FaceMLDataDB {
final person = mapRowToPerson(maps.first); final person = mapRowToPerson(maps.first);
final List<int> fileId = [recentFileID]; final List<int> fileId = [recentFileID];
int? avatarFileId; int? avatarFileId;
if (person.attr.avatarFaceId != null) { if (person.data.avatarFaceId != null) {
avatarFileId = int.tryParse(person.attr.avatarFaceId!.split('-')[0]); avatarFileId = int.tryParse(person.data.avatarFaceId!.split('-')[0]);
if (avatarFileId != null) { if (avatarFileId != null) {
fileId.add(avatarFileId); fileId.add(avatarFileId);
} }
@ -488,7 +488,7 @@ class FaceMLDataDB {
await db.execute(fcClusterIDIndex); await db.execute(fcClusterIDIndex);
} }
Future<void> insert(Person p, int cluserID) async { Future<void> insert(PersonEntity p, int cluserID) async {
debugPrint("inserting person"); debugPrint("inserting person");
final db = await instance.database; final db = await instance.database;
await db.insert( await db.insert(
@ -506,7 +506,7 @@ class FaceMLDataDB {
); );
} }
Future<void> updatePerson(Person p) async { Future<void> updatePerson(PersonEntity p) async {
final db = await instance.database; final db = await instance.database;
await db.update( await db.update(
personTable, personTable,
@ -639,10 +639,11 @@ class FaceMLDataDB {
return result; return result;
} }
Future<(Map<int, Person>, Map<String, Person>)> getClusterIdToPerson() async { Future<(Map<int, PersonEntity>, Map<String, PersonEntity>)>
getClusterIdToPerson() async {
final db = await instance.database; final db = await instance.database;
final List<Person> persons = await getPersons(); final List<PersonEntity> persons = await getPersons();
final Map<String, Person> personMap = {}; final Map<String, PersonEntity> personMap = {};
for (final p in persons) { for (final p in persons) {
personMap[p.remoteID] = p; personMap[p.remoteID] = p;
} }
@ -650,9 +651,9 @@ class FaceMLDataDB {
'SELECT $personIdColumn, $cluserIDColumn FROM $clusterPersonTable', 'SELECT $personIdColumn, $cluserIDColumn FROM $clusterPersonTable',
); );
final Map<int, Person> result = {}; final Map<int, PersonEntity> result = {};
for (final map in maps) { for (final map in maps) {
final Person? p = personMap[map[personIdColumn] as String]; final PersonEntity? p = personMap[map[personIdColumn] as String];
if (p != null) { if (p != null) {
result[map[cluserIDColumn] as int] = p; result[map[cluserIDColumn] as int] = p;
} else { } else {
@ -664,7 +665,7 @@ class FaceMLDataDB {
return (result, personMap); return (result, personMap);
} }
Future<List<Person>> getPersons() async { Future<List<PersonEntity>> getPersons() async {
final db = await instance.database; final db = await instance.database;
final List<Map<String, dynamic>> maps = await db.query( final List<Map<String, dynamic>> maps = await db.query(
personTable, personTable,
@ -714,7 +715,10 @@ class FaceMLDataDB {
await db.execute(createClusterSummaryTable); await db.execute(createClusterSummaryTable);
} }
Future<void> removeFilesFromPerson(List<EnteFile> files, Person p) async { Future<void> removeFilesFromPerson(
List<EnteFile> files,
PersonEntity p,
) async {
final db = await instance.database; final db = await instance.database;
final faceIdsResult = await db.rawQuery( final faceIdsResult = await db.rawQuery(
'SELECT $fcFaceId FROM $faceClustersTable LEFT JOIN $clusterPersonTable ' 'SELECT $fcFaceId FROM $faceClustersTable LEFT JOIN $clusterPersonTable '

View file

@ -50,6 +50,7 @@ const dropFaceClustersTable = 'DROP TABLE IF EXISTS $faceClustersTable';
const personTable = 'person'; const personTable = 'person';
const idColumn = 'id'; const idColumn = 'id';
const nameColumn = 'name'; const nameColumn = 'name';
const enteUserIdColumn = 'ente_user_id';
const personHiddenColumn = 'hidden'; const personHiddenColumn = 'hidden';
const clusterToFaceIdJson = 'clusterToFaceIds'; const clusterToFaceIdJson = 'clusterToFaceIds';
const coverFaceIDColumn = 'cover_face_id'; const coverFaceIDColumn = 'cover_face_id';

View file

@ -25,25 +25,26 @@ bool sqlIntToBool(int? value, {bool defaultValue = false}) {
} }
} }
Map<String, dynamic> mapPersonToRow(Person p) { Map<String, dynamic> mapPersonToRow(PersonEntity p) {
return { return {
idColumn: p.remoteID, idColumn: p.remoteID,
nameColumn: p.attr.name, nameColumn: p.data.name,
personHiddenColumn: boolToSQLInt(p.attr.isHidden), personHiddenColumn: boolToSQLInt(p.data.isHidden),
coverFaceIDColumn: p.attr.avatarFaceId, coverFaceIDColumn: p.data.avatarFaceId,
clusterToFaceIdJson: jsonEncode(p.attr.faces.toList()), clusterToFaceIdJson:
p.data.assigned != null ? jsonEncode(p.data.assigned!.toList()) : '{}',
}; };
} }
Person mapRowToPerson(Map<String, dynamic> row) { PersonEntity mapRowToPerson(Map<String, dynamic> row) {
return Person( return PersonEntity(
row[idColumn] as String, row[idColumn] as String,
PersonAttr( PersonData(
name: row[nameColumn] as String, name: row[nameColumn] as String,
isHidden: sqlIntToBool(row[personHiddenColumn] as int), isHidden: sqlIntToBool(row[personHiddenColumn] as int),
avatarFaceId: row[coverFaceIDColumn] as String?, avatarFaceId: row[coverFaceIDColumn] as String?,
faces: (jsonDecode(row[clusterToFaceIdJson]) as List) assigned: (json.decode(row[clusterToFaceIdJson] as String) as List)
.map((e) => e.toString()) .map((e) => ClusterInfo.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
), ),
); );

View file

@ -1,47 +1,77 @@
class Person { // PersonEntity represents information about a Person in the context of FaceClustering that is stored.
// On the remote server, the PersonEntity is stored as {Entity} with type person.
// On the device, this information is stored as [LocalEntityData] with type person.
class PersonEntity {
final String remoteID; final String remoteID;
final PersonAttr attr; final PersonData data;
Person( PersonEntity(
this.remoteID, this.remoteID,
this.attr, this.data,
); );
// copyWith // copyWith
Person copyWith({ PersonEntity copyWith({
String? remoteID, String? remoteID,
PersonAttr? attr, PersonData? data,
}) { }) {
return Person( return PersonEntity(
remoteID ?? this.remoteID, remoteID ?? this.remoteID,
attr ?? this.attr, data ?? this.data,
); );
} }
} }
class PersonAttr { class ClusterInfo {
final int id;
final Set<String> faces;
ClusterInfo({
required this.id,
required this.faces,
});
// toJson
Map<String, dynamic> toJson() => {
'id': id,
'faces': faces.toList(),
};
// from Json
factory ClusterInfo.fromJson(Map<String, dynamic> json) {
return ClusterInfo(
id: json['id'] as int,
faces: Set<String>.from(json['faces'] as List<String>),
);
}
}
class PersonData {
final String name; final String name;
final bool isHidden; final bool isHidden;
String? avatarFaceId; String? avatarFaceId;
final List<String> faces; List<ClusterInfo>? assigned = List<ClusterInfo>.empty();
List<ClusterInfo>? rejected = List<ClusterInfo>.empty();
final String? birthDate; final String? birthDate;
PersonAttr({
PersonData({
required this.name, required this.name,
required this.faces, this.assigned,
this.rejected,
this.avatarFaceId, this.avatarFaceId,
this.isHidden = false, this.isHidden = false,
this.birthDate, this.birthDate,
}); });
// copyWith // copyWith
PersonAttr copyWith({ PersonData copyWith({
String? name, String? name,
List<String>? faces, List<ClusterInfo>? assigned,
String? avatarFaceId, String? avatarFaceId,
bool? isHidden, bool? isHidden,
int? version,
String? birthDate, String? birthDate,
}) { }) {
return PersonAttr( return PersonData(
name: name ?? this.name, name: name ?? this.name,
faces: faces ?? this.faces, assigned: assigned ?? this.assigned,
avatarFaceId: avatarFaceId ?? this.avatarFaceId, avatarFaceId: avatarFaceId ?? this.avatarFaceId,
isHidden: isHidden ?? this.isHidden, isHidden: isHidden ?? this.isHidden,
birthDate: birthDate ?? this.birthDate, birthDate: birthDate ?? this.birthDate,
@ -51,20 +81,26 @@ class PersonAttr {
// toJson // toJson
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'name': name, 'name': name,
'faces': faces.toList(), 'assigned': assigned?.map((e) => e.toJson()).toList(),
'rejected': rejected?.map((e) => e.toJson()).toList(),
'avatarFaceId': avatarFaceId, 'avatarFaceId': avatarFaceId,
'isHidden': isHidden, 'isHidden': isHidden,
'birthDate': birthDate, 'birthDate': birthDate,
}; };
// fromJson // fromJson
factory PersonAttr.fromJson(Map<String, dynamic> json) { factory PersonData.fromJson(Map<String, dynamic> json) {
return PersonAttr( return PersonData(
name: json['name'] as String, name: json['name'] as String,
faces: List<String>.from(json['faces'] as List<dynamic>), assigned: List<ClusterInfo>.from(
(json['assigned'] as List<dynamic>).map((e) => ClusterInfo.fromJson(e)),
),
rejected: List<ClusterInfo>.from(
(json['rejected'] as List<dynamic>).map((e) => ClusterInfo.fromJson(e)),
),
avatarFaceId: json['avatarFaceId'] as String?, avatarFaceId: json['avatarFaceId'] as String?,
isHidden: json['isHidden'] as bool? ?? false, isHidden: json['isHidden'] as bool? ?? false,
birthDate: json['birthDatae'] as String?, birthDate: json['birthDate'] as String?,
); );
} }
} }

View file

@ -233,6 +233,7 @@ class EnteFile {
} }
String get downloadUrl { String get downloadUrl {
return "http://localhost:8700/$uploadedFileID";
final endpoint = Configuration.instance.getHttpEndpoint(); final endpoint = Configuration.instance.getHttpEndpoint();
if (endpoint != kDefaultProductionEndpoint || if (endpoint != kDefaultProductionEndpoint ||
FeatureFlagService.instance.disableCFWorker()) { FeatureFlagService.instance.disableCFWorker()) {
@ -247,6 +248,7 @@ class EnteFile {
} }
String get thumbnailUrl { String get thumbnailUrl {
return "http://localhost:8700/thumb/$uploadedFileID";
final endpoint = Configuration.instance.getHttpEndpoint(); final endpoint = Configuration.instance.getHttpEndpoint();
if (endpoint != kDefaultProductionEndpoint || if (endpoint != kDefaultProductionEndpoint ||
FeatureFlagService.instance.disableCFWorker()) { FeatureFlagService.instance.disableCFWorker()) {

View file

@ -1,6 +1,7 @@
import "package:equatable/equatable.dart"; import "package:equatable/equatable.dart";
import "package:photos/models/api/entity/type.dart"; import "package:photos/models/api/entity/type.dart";
// LocalEntityData is a class that represents the data of an entity stored locally.
class LocalEntityData { class LocalEntityData {
final String id; final String id;
final EntityType type; final EntityType type;

View file

@ -48,7 +48,7 @@ class ClusterFeedbackService {
/// Returns a map of person's clusterID to map of closest clusterID to with disstance /// Returns a map of person's clusterID to map of closest clusterID to with disstance
Future<Map<int, List<(int, double)>>> getSuggestionsUsingMean( Future<Map<int, List<(int, double)>>> getSuggestionsUsingMean(
Person p, { PersonEntity p, {
double maxClusterDistance = 0.4, double maxClusterDistance = 0.4,
}) async { }) async {
// Get all the cluster data // Get all the cluster data
@ -58,7 +58,7 @@ class ClusterFeedbackService {
final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID); final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID);
final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID); final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID);
dev.log( dev.log(
'existing clusters for ${p.attr.name} are $personClusters', 'existing clusters for ${p.data.name} are $personClusters',
name: "ClusterFeedbackService", name: "ClusterFeedbackService",
); );
@ -81,7 +81,7 @@ class ClusterFeedbackService {
// log suggestions // log suggestions
for (final entry in suggestions.entries) { for (final entry in suggestions.entries) {
dev.log( dev.log(
' ${entry.value.length} suggestion for ${p.attr.name} for cluster ID ${entry.key} are suggestions ${entry.value}}', ' ${entry.value.length} suggestion for ${p.data.name} for cluster ID ${entry.key} are suggestions ${entry.value}}',
name: "ClusterFeedbackService", name: "ClusterFeedbackService",
); );
} }
@ -93,7 +93,7 @@ class ClusterFeedbackService {
/// 2. distance: the distance between the person's cluster and the suggestion /// 2. distance: the distance between the person's cluster and the suggestion
/// 3. usedMean: whether the suggestion was found using the mean (true) or the median (false) /// 3. usedMean: whether the suggestion was found using the mean (true) or the median (false)
Future<List<(int, double, bool)>> getSuggestionsUsingMedian( Future<List<(int, double, bool)>> getSuggestionsUsingMedian(
Person p, { PersonEntity p, {
int sampleSize = 50, int sampleSize = 50,
double maxMedianDistance = 0.65, double maxMedianDistance = 0.65,
double goodMedianDistance = 0.55, double goodMedianDistance = 0.55,
@ -107,7 +107,7 @@ class ClusterFeedbackService {
final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID); final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID);
final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID); final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID);
dev.log( dev.log(
'existing clusters for ${p.attr.name} are $personClusters', 'existing clusters for ${p.data.name} are $personClusters',
name: "getSuggestionsUsingMedian", name: "getSuggestionsUsingMedian",
); );
@ -267,11 +267,11 @@ class ClusterFeedbackService {
/// 3. bool: whether the suggestion was found using the mean (true) or the median (false) /// 3. bool: whether the suggestion was found using the mean (true) or the median (false)
/// 4. List<EnteFile>: the files in the cluster /// 4. List<EnteFile>: the files in the cluster
Future<List<ClusterSuggestion>> getSuggestionForPerson( Future<List<ClusterSuggestion>> getSuggestionForPerson(
Person person, { PersonEntity person, {
bool extremeFilesFirst = true, bool extremeFilesFirst = true,
}) async { }) async {
_logger.info( _logger.info(
'getClusterFilesForPersonID ${kDebugMode ? person.attr.name : person.remoteID}', 'getClusterFilesForPersonID ${kDebugMode ? person.data.name : person.remoteID}',
); );
try { try {
@ -325,7 +325,7 @@ class ClusterFeedbackService {
} }
} }
Future<void> removeFilesFromPerson(List<EnteFile> files, Person p) { Future<void> removeFilesFromPerson(List<EnteFile> files, PersonEntity p) {
return FaceMLDataDB.instance.removeFilesFromPerson(files, p); return FaceMLDataDB.instance.removeFilesFromPerson(files, p);
} }
@ -333,13 +333,13 @@ class ClusterFeedbackService {
return FaceMLDataDB.instance.removeFilesFromCluster(files, clusterID); return FaceMLDataDB.instance.removeFilesFromCluster(files, clusterID);
} }
Future<bool> checkAndDoAutomaticMerges(Person p) async { Future<bool> checkAndDoAutomaticMerges(PersonEntity p) async {
final faceMlDb = FaceMLDataDB.instance; final faceMlDb = FaceMLDataDB.instance;
final allClusterIdsToCountMap = (await faceMlDb.clusterIdToFaceCount()); final allClusterIdsToCountMap = (await faceMlDb.clusterIdToFaceCount());
final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID); final ignoredClusters = await faceMlDb.getPersonIgnoredClusters(p.remoteID);
final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID); final personClusters = await faceMlDb.getPersonClusterIDs(p.remoteID);
dev.log( dev.log(
'existing clusters for ${p.attr.name} are $personClusters', 'existing clusters for ${p.data.name} are $personClusters',
name: "ClusterFeedbackService", name: "ClusterFeedbackService",
); );
@ -361,7 +361,7 @@ class ClusterFeedbackService {
if (suggestions.isEmpty) { if (suggestions.isEmpty) {
dev.log( dev.log(
'No automatic merge suggestions for ${p.attr.name}', 'No automatic merge suggestions for ${p.data.name}',
name: "ClusterFeedbackService", name: "ClusterFeedbackService",
); );
return false; return false;
@ -370,7 +370,7 @@ class ClusterFeedbackService {
// log suggestions // log suggestions
for (final entry in suggestions.entries) { for (final entry in suggestions.entries) {
dev.log( dev.log(
' ${entry.value.length} suggestion for ${p.attr.name} for cluster ID ${entry.key} are suggestions ${entry.value}}', ' ${entry.value.length} suggestion for ${p.data.name} for cluster ID ${entry.key} are suggestions ${entry.value}}',
name: "ClusterFeedbackService", name: "ClusterFeedbackService",
); );
} }
@ -677,7 +677,7 @@ class ClusterFeedbackService {
} }
Future<void> _sortSuggestionsOnDistanceToPerson( Future<void> _sortSuggestionsOnDistanceToPerson(
Person person, PersonEntity person,
List<ClusterSuggestion> suggestions, List<ClusterSuggestion> suggestions,
) async { ) async {
if (suggestions.isEmpty) { if (suggestions.isEmpty) {

View file

@ -0,0 +1,10 @@
import "package:photos/face/db.dart";
import "package:photos/services/entity_service.dart";
import "package:shared_preferences/shared_preferences.dart";
class PersonService {
final EntityService entityService;
final FaceMLDataDB faceMLDataDB;
final SharedPreferences _prefs;
PersonService(this.entityService, this.faceMLDataDB, this._prefs);
}

View file

@ -753,7 +753,7 @@ class SearchService {
} }
final cluserIds = fileIdToClusterID[f.uploadedFileID ?? -1]!; final cluserIds = fileIdToClusterID[f.uploadedFileID ?? -1]!;
for (final cluster in cluserIds) { for (final cluster in cluserIds) {
final Person? p = clusterIDToPerson[cluster]; final PersonEntity? p = clusterIDToPerson[cluster];
if (p != null) { if (p != null) {
if (personIdToFiles.containsKey(p.remoteID)) { if (personIdToFiles.containsKey(p.remoteID)) {
personIdToFiles[p.remoteID]!.add(f); personIdToFiles[p.remoteID]!.add(f);
@ -781,11 +781,11 @@ class SearchService {
if (files.isEmpty) { if (files.isEmpty) {
continue; continue;
} }
final Person p = personIdToPerson[personID]!; final PersonEntity p = personIdToPerson[personID]!;
facesResult.add( facesResult.add(
GenericSearchResult( GenericSearchResult(
ResultType.faces, ResultType.faces,
p.attr.name, p.data.name,
files, files,
params: { params: {
kPersonParamID: personID, kPersonParamID: personID,
@ -795,7 +795,7 @@ class SearchService {
routeToPage( routeToPage(
ctx, ctx,
PeoplePage( PeoplePage(
tagPrefix: "${ResultType.faces.toString()}_${p.attr.name}", tagPrefix: "${ResultType.faces.toString()}_${p.data.name}",
person: p, person: p,
), ),
); );
@ -813,7 +813,7 @@ class SearchService {
final files = clusterIdToFiles[clusterId]!; final files = clusterIdToFiles[clusterId]!;
// final String clusterName = "ID:$clusterId, ${files.length}"; // final String clusterName = "ID:$clusterId, ${files.length}";
final String clusterName = "${files.length}"; final String clusterName = "${files.length}";
final Person? p = clusterIDToPerson[clusterId]; final PersonEntity? p = clusterIDToPerson[clusterId];
if (p != null) { if (p != null) {
throw Exception("Person should be null"); throw Exception("Person should be null");
} }

View file

@ -12,7 +12,7 @@ import "package:photos/ui/viewer/actions/file_selection_actions_widget.dart";
class BottomActionBarWidget extends StatelessWidget { class BottomActionBarWidget extends StatelessWidget {
final GalleryType galleryType; final GalleryType galleryType;
final Collection? collection; final Collection? collection;
final Person? person; final PersonEntity? person;
final int? clusterID; final int? clusterID;
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final VoidCallback? onCancel; final VoidCallback? onCancel;

View file

@ -243,13 +243,13 @@ class _FaceDebugSectionWidgetState extends State<FaceDebugSectionWidget> {
trailingIconIsMuted: true, trailingIconIsMuted: true,
onTap: () async { onTap: () async {
try { try {
final List<Person> persons = final List<PersonEntity> persons =
await FaceMLDataDB.instance.getPersons(); await FaceMLDataDB.instance.getPersons();
final EnteWatch w = EnteWatch('feedback')..start(); final EnteWatch w = EnteWatch('feedback')..start();
for (final Person p in persons) { for (final PersonEntity p in persons) {
await ClusterFeedbackService.instance await ClusterFeedbackService.instance
.getSuggestionsUsingMean(p); .getSuggestionsUsingMean(p);
w.logAndReset('suggestion calculated for ${p.attr.name}'); w.logAndReset('suggestion calculated for ${p.data.name}');
} }
w.log("done with feedback"); w.log("done with feedback");
showShortToast(context, "done avg"); showShortToast(context, "done avg");

View file

@ -45,7 +45,7 @@ class FileSelectionActionsWidget extends StatefulWidget {
final Collection? collection; final Collection? collection;
final DeviceCollection? deviceCollection; final DeviceCollection? deviceCollection;
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final Person? person; final PersonEntity? person;
final int? clusterID; final int? clusterID;
const FileSelectionActionsWidget( const FileSelectionActionsWidget(
@ -130,7 +130,7 @@ class _FileSelectionActionsWidgetState
items.add( items.add(
SelectionActionButton( SelectionActionButton(
icon: Icons.remove_circle_outline, icon: Icons.remove_circle_outline,
labelText: 'Not ${widget.person!.attr.name}?', labelText: 'Not ${widget.person!.data.name}?',
onTap: anyUploadedFiles ? _onNotpersonClicked : null, onTap: anyUploadedFiles ? _onNotpersonClicked : null,
), ),
); );
@ -653,8 +653,8 @@ class _FileSelectionActionsWidgetState
Future<void> _setPersonCover() async { Future<void> _setPersonCover() async {
final EnteFile file = widget.selectedFiles.files.first; final EnteFile file = widget.selectedFiles.files.first;
final Person newPerson = widget.person!.copyWith( final PersonEntity newPerson = widget.person!.copyWith(
attr: widget.person!.attr data: widget.person!.data
.copyWith(avatarFaceId: file.uploadedFileID.toString()), .copyWith(avatarFaceId: file.uploadedFileID.toString()),
); );
await FaceMLDataDB.instance.updatePerson(newPerson); await FaceMLDataDB.instance.updatePerson(newPerson);
@ -686,7 +686,7 @@ class _FileSelectionActionsWidgetState
isInAlert: true, isInAlert: true,
), ),
], ],
title: "Remove these photos for ${widget.person!.attr.name}?", title: "Remove these photos for ${widget.person!.data.name}?",
actionSheetType: ActionSheetType.defaultActionSheet, actionSheetType: ActionSheetType.defaultActionSheet,
); );
if (actionResult?.action != null) { if (actionResult?.action != null) {

View file

@ -11,7 +11,7 @@ class FileSelectionOverlayBar extends StatefulWidget {
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final Collection? collection; final Collection? collection;
final Color? backgroundColor; final Color? backgroundColor;
final Person? person; final PersonEntity? person;
final int? clusterID; final int? clusterID;
const FileSelectionOverlayBar( const FileSelectionOverlayBar(

View file

@ -20,7 +20,7 @@ import "package:photos/utils/thumbnail_util.dart";
class FaceWidget extends StatelessWidget { class FaceWidget extends StatelessWidget {
final EnteFile file; final EnteFile file;
final Face face; final Face face;
final Person? person; final PersonEntity? person;
final int? clusterID; final int? clusterID;
final bool highlight; final bool highlight;
@ -114,7 +114,7 @@ class FaceWidget extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
if (person != null) if (person != null)
Text( Text(
person!.attr.name.trim(), person!.data.name.trim(),
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
@ -237,7 +237,7 @@ class FaceWidget extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
if (person != null) if (person != null)
Text( Text(
person!.attr.name.trim(), person!.data.name.trim(),
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,

View file

@ -74,7 +74,7 @@ class FacesItemWidget extends StatelessWidget {
final faceWidgets = <FaceWidget>[]; final faceWidgets = <FaceWidget>[];
for (final Face face in faces) { for (final Face face in faces) {
final int? clusterID = faceIdsToClusterIds[face.faceID]; final int? clusterID = faceIdsToClusterIds[face.faceID];
final Person? person = clusterIDToPerson[clusterID]; final PersonEntity? person = clusterIDToPerson[clusterID];
final highlight = final highlight =
(clusterID == lastViewedClusterID) && (person == null); (clusterID == lastViewedClusterID) && (person == null);
faceWidgets.add( faceWidgets.add(

View file

@ -178,7 +178,7 @@ class _PersonActionSheetState extends State<PersonActionSheet> {
return Flexible( return Flexible(
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(16, 24, 4, 0), padding: const EdgeInsets.fromLTRB(16, 24, 4, 0),
child: FutureBuilder<List<Person>>( child: FutureBuilder<List<PersonEntity>>(
future: _getPersons(), future: _getPersons(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasError) { if (snapshot.hasError) {
@ -186,11 +186,11 @@ class _PersonActionSheetState extends State<PersonActionSheet> {
//Need to show an error on the UI here //Need to show an error on the UI here
return const SizedBox.shrink(); return const SizedBox.shrink();
} else if (snapshot.hasData) { } else if (snapshot.hasData) {
final persons = snapshot.data as List<Person>; final persons = snapshot.data as List<PersonEntity>;
final searchResults = _searchQuery.isNotEmpty final searchResults = _searchQuery.isNotEmpty
? persons ? persons
.where( .where(
(element) => element.attr.name (element) => element.data.name
.toLowerCase() .toLowerCase()
.contains(_searchQuery), .contains(_searchQuery),
) )
@ -270,9 +270,9 @@ class _PersonActionSheetState extends State<PersonActionSheet> {
} }
try { try {
final String id = const Uuid().v4().toString(); final String id = const Uuid().v4().toString();
final Person p = Person( final PersonEntity p = PersonEntity(
id, id,
PersonAttr(name: text, faces: <String>[]), PersonData(name: text, assigned: <ClusterInfo>[]),
); );
await FaceMLDataDB.instance.insert(p, clusterID); await FaceMLDataDB.instance.insert(p, clusterID);
final bool extraPhotosFound = await ClusterFeedbackService.instance final bool extraPhotosFound = await ClusterFeedbackService.instance
@ -295,7 +295,7 @@ class _PersonActionSheetState extends State<PersonActionSheet> {
} }
} }
Future<List<Person>> _getPersons() async { Future<List<PersonEntity>> _getPersons() async {
return FaceMLDataDB.instance.getPersons(); return FaceMLDataDB.instance.getPersons();
} }
} }

View file

@ -24,7 +24,7 @@ class ClusterAppBar extends StatefulWidget {
final String? title; final String? title;
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final int clusterID; final int clusterID;
final Person? person; final PersonEntity? person;
const ClusterAppBar( const ClusterAppBar(
this.type, this.type,

View file

@ -27,7 +27,7 @@ class ClusterPage extends StatefulWidget {
final bool enableGrouping; final bool enableGrouping;
final String tagPrefix; final String tagPrefix;
final int clusterID; final int clusterID;
final Person? personID; final PersonEntity? personID;
final String appendTitle; final String appendTitle;
static const GalleryType appBarType = GalleryType.cluster; static const GalleryType appBarType = GalleryType.cluster;
@ -137,7 +137,7 @@ class _ClusterPageState extends State<ClusterPage> {
context, context,
clusterID: widget.clusterID, clusterID: widget.clusterID,
); );
if (result != null && result is Person) { if (result != null && result is PersonEntity) {
Navigator.pop(context); Navigator.pop(context);
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result)); routeToPage(context, PeoplePage(person: result));

View file

@ -22,7 +22,7 @@ class PeopleAppBar extends StatefulWidget {
final GalleryType type; final GalleryType type;
final String? title; final String? title;
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final Person person; final PersonEntity person;
const PeopleAppBar( const PeopleAppBar(
this.type, this.type,
@ -100,7 +100,7 @@ class _AppBarWidgetState extends State<PeopleAppBar> {
submitButtonLabel: S.of(context).done, submitButtonLabel: S.of(context).done,
hintText: S.of(context).enterAlbumName, hintText: S.of(context).enterAlbumName,
alwaysShowSuccessState: true, alwaysShowSuccessState: true,
initialValue: widget.person.attr.name, initialValue: widget.person.data.name,
textCapitalization: TextCapitalization.words, textCapitalization: TextCapitalization.words,
onSubmit: (String text) async { onSubmit: (String text) async {
// indicates user cancelled the rename request // indicates user cancelled the rename request
@ -110,7 +110,7 @@ class _AppBarWidgetState extends State<PeopleAppBar> {
try { try {
final updatePerson = widget.person final updatePerson = widget.person
.copyWith(attr: widget.person.attr.copyWith(name: text)); .copyWith(data: widget.person.data.copyWith(name: text));
await FaceMLDataDB.instance.updatePerson(updatePerson); await FaceMLDataDB.instance.updatePerson(updatePerson);
if (mounted) { if (mounted) {
_appBarTitle = text; _appBarTitle = text;

View file

@ -20,7 +20,7 @@ import "package:photos/ui/viewer/people/people_app_bar.dart";
class PeoplePage extends StatefulWidget { class PeoplePage extends StatefulWidget {
final String tagPrefix; final String tagPrefix;
final Person person; final PersonEntity person;
static const GalleryType appBarType = GalleryType.peopleTag; static const GalleryType appBarType = GalleryType.peopleTag;
static const GalleryType overlayType = GalleryType.peopleTag; static const GalleryType overlayType = GalleryType.peopleTag;
@ -86,13 +86,13 @@ class _PeoplePageState extends State<PeoplePage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_logger.info("Building for ${widget.person.attr.name}"); _logger.info("Building for ${widget.person.data.name}");
return Scaffold( return Scaffold(
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0), preferredSize: const Size.fromHeight(50.0),
child: PeopleAppBar( child: PeopleAppBar(
GalleryType.peopleTag, GalleryType.peopleTag,
widget.person.attr.name, widget.person.data.name,
_selectedFiles, _selectedFiles,
widget.person, widget.person,
), ),

View file

@ -14,7 +14,7 @@ import "package:photos/ui/viewer/people/cluster_page.dart";
import "package:photos/ui/viewer/search/result/person_face_widget.dart"; import "package:photos/ui/viewer/search/result/person_face_widget.dart";
class PersonClusters extends StatefulWidget { class PersonClusters extends StatefulWidget {
final Person person; final PersonEntity person;
const PersonClusters( const PersonClusters(
this.person, { this.person, {
@ -31,7 +31,7 @@ class _PersonClustersState extends State<PersonClusters> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(widget.person.attr.name), title: Text(widget.person.data.name),
), ),
body: FutureBuilder<Map<int, List<EnteFile>>>( body: FutureBuilder<Map<int, List<EnteFile>>>(
future: SearchService.instance future: SearchService.instance

View file

@ -15,7 +15,7 @@ import "package:photos/ui/viewer/people/cluster_page.dart";
import "package:photos/ui/viewer/search/result/person_face_widget.dart"; import "package:photos/ui/viewer/search/result/person_face_widget.dart";
class PersonReviewClusterSuggestion extends StatefulWidget { class PersonReviewClusterSuggestion extends StatefulWidget {
final Person person; final PersonEntity person;
const PersonReviewClusterSuggestion( const PersonReviewClusterSuggestion(
this.person, { this.person, {
@ -55,7 +55,7 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
if (snapshot.data!.isEmpty) { if (snapshot.data!.isEmpty) {
return Center( return Center(
child: Text( child: Text(
"No suggestions for ${widget.person.attr.name}", "No suggestions for ${widget.person.data.name}",
style: getEnteTextTheme(context).largeMuted, style: getEnteTextTheme(context).largeMuted,
), ),
); );
@ -160,8 +160,8 @@ class _PersonClustersState extends State<PersonReviewClusterSuggestion> {
), ),
Text( Text(
files.length > 1 files.length > 1
? "These photos belong to ${widget.person.attr.name}?" ? "These photos belong to ${widget.person.data.name}?"
: "This photo belongs to ${widget.person.attr.name}?", : "This photo belongs to ${widget.person.data.name}?",
style: getEnteTextTheme(context).largeMuted, style: getEnteTextTheme(context).largeMuted,
), ),
const SizedBox(height: 24), const SizedBox(height: 24),

View file

@ -2,7 +2,7 @@ import "package:flutter/material.dart";
import "package:photos/face/model/person.dart"; import "package:photos/face/model/person.dart";
class PersonRowItem extends StatelessWidget { class PersonRowItem extends StatelessWidget {
final Person person; final PersonEntity person;
final VoidCallback onTap; final VoidCallback onTap;
const PersonRowItem({ const PersonRowItem({
@ -15,9 +15,9 @@ class PersonRowItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
leading: CircleAvatar( leading: CircleAvatar(
child: Text(person.attr.name.substring(0, 1)), child: Text(person.data.name.substring(0, 1)),
), ),
title: Text(person.attr.name), title: Text(person.data.name),
onTap: onTap, onTap: onTap,
); );
} }