mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
refactor: unify person model (#30659)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
943c11c019
commit
52edcc0c74
16 changed files with 34 additions and 78 deletions
|
|
@ -3,32 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||
|
||||
part 'person.model.freezed.dart';
|
||||
|
||||
// TODO: Remove PersonDto once Isar is removed
|
||||
@freezed
|
||||
abstract class PersonDto with _$PersonDto {
|
||||
const factory PersonDto({
|
||||
required String id,
|
||||
DateTime? birthDate,
|
||||
required bool isHidden,
|
||||
required String name,
|
||||
required String thumbnailPath,
|
||||
DateTime? updatedAt,
|
||||
}) = _PersonDto;
|
||||
}
|
||||
|
||||
// Model for a person stored in the server
|
||||
@freezed
|
||||
abstract class DriftPerson with _$DriftPerson {
|
||||
const factory DriftPerson({
|
||||
required String id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required String ownerId,
|
||||
required String name,
|
||||
String? faceAssetId,
|
||||
required bool isFavorite,
|
||||
required bool isHidden,
|
||||
required String? color,
|
||||
DateTime? birthDate,
|
||||
}) = _DriftPerson;
|
||||
abstract class Person with _$Person {
|
||||
const factory Person({required String id, required String name, DateTime? updatedAt, DateTime? birthDate}) = _Person;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@ class DriftPeopleService {
|
|||
|
||||
const DriftPeopleService(this._repository, this._personApiRepository);
|
||||
|
||||
Future<DriftPerson?> get(String personId) {
|
||||
Future<Person?> get(String personId) {
|
||||
return _repository.get(personId);
|
||||
}
|
||||
|
||||
Future<List<DriftPerson>> getAssetPeople(String assetId) {
|
||||
Future<List<Person>> getAssetPeople(String assetId) {
|
||||
return _repository.getAssetPeople(assetId);
|
||||
}
|
||||
|
||||
Future<List<DriftPerson>> getAllPeople({int minFaces = 3}) {
|
||||
Future<List<Person>> getAllPeople({int minFaces = 3}) {
|
||||
return _repository.getAllPeople(minFaces: minFaces);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ class DriftPeopleRepository extends DriftDatabaseRepository {
|
|||
final Drift _db;
|
||||
const DriftPeopleRepository(this._db) : super(_db);
|
||||
|
||||
Future<DriftPerson?> get(String personId) async {
|
||||
Future<Person?> get(String personId) async {
|
||||
final query = _db.select(_db.personEntity)..where((row) => row.id.equals(personId));
|
||||
|
||||
final result = await query.getSingleOrNull();
|
||||
return result?.toDto();
|
||||
}
|
||||
|
||||
Future<List<DriftPerson>> getAssetPeople(String assetId) async {
|
||||
Future<List<Person>> getAssetPeople(String assetId) async {
|
||||
// An asset can have multiple face records for the same person (e.g., metadata
|
||||
// imports alongside ML detections). Use a subquery instead of a join so each
|
||||
// person is returned once, regardless of how many of their faces are on the asset
|
||||
|
|
@ -33,7 +33,7 @@ class DriftPeopleRepository extends DriftDatabaseRepository {
|
|||
return query.map((row) => row.toDto()).get();
|
||||
}
|
||||
|
||||
Future<List<DriftPerson>> getAllPeople({int minFaces = 3}) async {
|
||||
Future<List<Person>> getAllPeople({int minFaces = 3}) async {
|
||||
final people = _db.personEntity;
|
||||
final faces = _db.assetFaceEntity;
|
||||
final assets = _db.remoteAssetEntity;
|
||||
|
|
@ -76,18 +76,5 @@ class DriftPeopleRepository extends DriftDatabaseRepository {
|
|||
}
|
||||
|
||||
extension on PersonEntityData {
|
||||
DriftPerson toDto() {
|
||||
return DriftPerson(
|
||||
id: id,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
ownerId: ownerId,
|
||||
name: name,
|
||||
faceAssetId: faceAssetId,
|
||||
isFavorite: isFavorite,
|
||||
isHidden: isHidden,
|
||||
color: color,
|
||||
birthDate: birthDate,
|
||||
);
|
||||
}
|
||||
Person toDto() => Person(id: id, updatedAt: updatedAt, name: name, birthDate: birthDate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ class SearchFilter {
|
|||
String? language;
|
||||
String? assetId;
|
||||
List<String>? tagIds;
|
||||
Set<PersonDto> people;
|
||||
Set<Person> people;
|
||||
SearchLocationFilter location;
|
||||
SearchCameraFilter camera;
|
||||
SearchDateFilter date;
|
||||
|
|
@ -250,7 +250,7 @@ class SearchFilter {
|
|||
String? language,
|
||||
String? ocr,
|
||||
String? assetId,
|
||||
Set<PersonDto>? people,
|
||||
Set<Person>? people,
|
||||
List<String>? tagIds,
|
||||
SearchLocationFilter? location,
|
||||
SearchCameraFilter? camera,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import 'package:immich_mobile/widgets/common/person_sliver_app_bar.dart';
|
|||
|
||||
@RoutePage()
|
||||
class DriftPersonPage extends ConsumerStatefulWidget {
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
|
||||
const DriftPersonPage({super.key, required this.person});
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ class DriftPersonPage extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _DriftPersonPageState extends ConsumerState<DriftPersonPage> {
|
||||
late DriftPerson _person;
|
||||
late Person _person;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
void showPeoplePicker() {
|
||||
var people = filter.value.people;
|
||||
|
||||
void handleOnSelect(Set<PersonDto> value) {
|
||||
void handleOnSelect(Set<Person> value) {
|
||||
people = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class PeopleDetails extends ConsumerWidget {
|
|||
|
||||
final peopleFuture = ref.watch(driftPeopleAssetProvider(asset.id));
|
||||
|
||||
Future<void> showNameEditModal(DriftPerson person) async {
|
||||
Future<void> showNameEditModal(Person person) async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
|
|
@ -96,7 +96,7 @@ class PeopleDetails extends ConsumerWidget {
|
|||
}
|
||||
|
||||
class _Avatar extends StatelessWidget {
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
final DateTime assetFileCreatedAt;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onNameTap;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
|||
import 'package:scroll_date_picker/scroll_date_picker.dart';
|
||||
|
||||
class DriftPersonBirthdayEditForm extends ConsumerStatefulWidget {
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
|
||||
const DriftPersonBirthdayEditForm({super.key, required this.person});
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import 'package:immich_mobile/utils/debug_print.dart';
|
|||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||
|
||||
class DriftPersonNameEditForm extends ConsumerStatefulWidget {
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
|
||||
const DriftPersonNameEditForm({super.key, required this.person});
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ final driftPeopleServiceProvider = Provider<DriftPeopleService>(
|
|||
(ref) => DriftPeopleService(ref.watch(driftPeopleRepositoryProvider), ref.watch(personApiRepositoryProvider)),
|
||||
);
|
||||
|
||||
final driftPeopleAssetProvider = FutureProvider.family<List<DriftPerson>, String>((ref, assetId) async {
|
||||
final driftPeopleAssetProvider = FutureProvider.family<List<Person>, String>((ref, assetId) async {
|
||||
final service = ref.watch(driftPeopleServiceProvider);
|
||||
return service.getAssetPeople(assetId);
|
||||
});
|
||||
|
||||
final driftGetAllPeopleProvider = FutureProvider<List<DriftPerson>>((ref) async {
|
||||
final driftGetAllPeopleProvider = FutureProvider<List<Person>>((ref) async {
|
||||
final service = ref.watch(driftPeopleServiceProvider);
|
||||
final prefs = await ref.watch(userMetadataPreferencesProvider.future);
|
||||
return service.getAllPeople(minFaces: prefs?.minimumFaces ?? 3);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:immich_mobile/domain/models/person.model.dart';
|
||||
import 'package:immich_mobile/services/person.service.dart';
|
||||
|
||||
final getAllPeopleProvider = FutureProvider.autoDispose<List<PersonDto>>((ref) async {
|
||||
final getAllPeopleProvider = FutureProvider.autoDispose<List<Person>>((ref) async {
|
||||
final PersonService personService = ref.read(personServiceProvider);
|
||||
|
||||
final people = await personService.getAllPeople();
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ class PersonApiRepository extends ApiRepository {
|
|||
|
||||
PersonApiRepository(this._api);
|
||||
|
||||
Future<List<PersonDto>> getAll() async {
|
||||
Future<List<Person>> getAll() async {
|
||||
final dto = await checkNull(_api.getAllPeople());
|
||||
return dto.people.map(_toPerson).toList();
|
||||
}
|
||||
|
||||
Future<PersonDto> update(String id, {String? name, DateTime? birthday}) async {
|
||||
Future<Person> update(String id, {String? name, DateTime? birthday}) async {
|
||||
final birthdayUtc = birthday == null ? null : DateTime.utc(birthday.year, birthday.month, birthday.day);
|
||||
final dto = PersonUpdateDto(
|
||||
name: name == null ? const Optional.absent() : Optional.present(name),
|
||||
|
|
@ -26,12 +26,6 @@ class PersonApiRepository extends ApiRepository {
|
|||
return _toPerson(response);
|
||||
}
|
||||
|
||||
static PersonDto _toPerson(PersonResponseDto dto) => PersonDto(
|
||||
birthDate: dto.birthDate,
|
||||
id: dto.id,
|
||||
isHidden: dto.isHidden,
|
||||
name: dto.name,
|
||||
thumbnailPath: dto.thumbnailPath,
|
||||
updatedAt: dto.updatedAt.orElse(null),
|
||||
);
|
||||
static Person _toPerson(PersonResponseDto dto) =>
|
||||
.new(birthDate: dto.birthDate, id: dto.id, name: dto.name, updatedAt: dto.updatedAt.value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class PersonService {
|
|||
final PersonApiRepository _personApiRepository;
|
||||
PersonService(this._personApiRepository);
|
||||
|
||||
Future<List<PersonDto>> getAllPeople() async {
|
||||
Future<List<Person>> getAllPeople() async {
|
||||
try {
|
||||
return await _personApiRepository.getAll();
|
||||
} catch (error, stack) {
|
||||
|
|
@ -21,7 +21,7 @@ class PersonService {
|
|||
}
|
||||
}
|
||||
|
||||
Future<PersonDto?> updateName(String id, String name) async {
|
||||
Future<Person?> updateName(String id, String name) async {
|
||||
try {
|
||||
return await _personApiRepository.update(id, name: name);
|
||||
} catch (error, stack) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ int _calculateAgeInMonths(DateTime birthDate, DateTime referenceDate) {
|
|||
(referenceDate.day < birthDate.day ? 1 : 0);
|
||||
}
|
||||
|
||||
Future<String?> showNameEditModal(BuildContext context, DriftPerson person) {
|
||||
Future<String?> showNameEditModal(BuildContext context, Person person) {
|
||||
return showDialog<String?>(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
|
|
@ -44,7 +44,7 @@ Future<String?> showNameEditModal(BuildContext context, DriftPerson person) {
|
|||
);
|
||||
}
|
||||
|
||||
Future<DateTime?> showBirthdayEditModal(BuildContext context, DriftPerson person) {
|
||||
Future<DateTime?> showBirthdayEditModal(BuildContext context, Person person) {
|
||||
return showDialog<DateTime?>(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class PersonSliverAppBar extends ConsumerStatefulWidget {
|
|||
required this.onBirthdayTap,
|
||||
});
|
||||
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
final VoidCallback onNameTap;
|
||||
final VoidCallback onBirthdayTap;
|
||||
final VoidCallback onShowOptions;
|
||||
|
|
@ -137,7 +137,7 @@ class _MesmerizingSliverAppBarState extends ConsumerState<PersonSliverAppBar> {
|
|||
|
||||
class _ExpandedBackground extends ConsumerStatefulWidget {
|
||||
final double scrollProgress;
|
||||
final DriftPerson person;
|
||||
final Person person;
|
||||
final VoidCallback onNameTap;
|
||||
final VoidCallback onBirthdayTap;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import 'package:immich_mobile/widgets/common/search_field.dart';
|
|||
class PeoplePicker extends HookConsumerWidget {
|
||||
const PeoplePicker({super.key, required this.onSelect, this.filter});
|
||||
|
||||
final Function(Set<PersonDto>) onSelect;
|
||||
final Set<PersonDto>? filter;
|
||||
final Function(Set<Person>) onSelect;
|
||||
final Set<Person>? filter;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -24,7 +24,7 @@ class PeoplePicker extends HookConsumerWidget {
|
|||
const imageSize = 60.0;
|
||||
final searchQuery = useState('');
|
||||
final people = ref.watch(getAllPeopleProvider);
|
||||
final selectedPeople = useState<Set<PersonDto>>(filter ?? {});
|
||||
final selectedPeople = useState<Set<Person>>(filter ?? {});
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue