[mob] Rename and add more attr to PersonEntity
This commit is contained in:
parent
2163201046
commit
f5a9679c0e
|
@ -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
|
||||||
|
|
|
@ -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 '
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
),
|
),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue