diff --git a/mobile/lib/domain/services/people.service.dart b/mobile/lib/domain/services/people.service.dart index 196cf1edbb..b7fa995c3f 100644 --- a/mobile/lib/domain/services/people.service.dart +++ b/mobile/lib/domain/services/people.service.dart @@ -31,4 +31,9 @@ class DriftPeopleService { await _personApiRepository.update(personId, birthday: birthday); return _repository.updateBirthday(personId, birthday); } + + Future updateVisibility(String personId, bool isHidden) async { + await _personApiRepository.update(personId, isHidden: isHidden); + return _repository.updateVisibility(personId, isHidden); + } } diff --git a/mobile/lib/infrastructure/repositories/people.repository.dart b/mobile/lib/infrastructure/repositories/people.repository.dart index c5c7bfdb9c..677dd79a94 100644 --- a/mobile/lib/infrastructure/repositories/people.repository.dart +++ b/mobile/lib/infrastructure/repositories/people.repository.dart @@ -73,6 +73,12 @@ class DriftPeopleRepository extends DriftDatabaseRepository { return query.write(PersonEntityCompanion(birthDate: Value(birthday), updatedAt: Value(DateTime.now()))); } + + Future updateVisibility(String personId, bool isHidden) { + final query = _db.update(_db.personEntity)..where((row) => row.id.equals(personId)); + + return query.write(PersonEntityCompanion(isHidden: Value(isHidden), updatedAt: Value(DateTime.now()))); + } } extension on PersonEntityData { diff --git a/mobile/lib/presentation/pages/drift_person.page.dart b/mobile/lib/presentation/pages/drift_person.page.dart index cad3b7b6a6..f3bde79820 100644 --- a/mobile/lib/presentation/pages/drift_person.page.dart +++ b/mobile/lib/presentation/pages/drift_person.page.dart @@ -2,14 +2,19 @@ import 'dart:async'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/person.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/people/person_option_sheet.widget.dart'; import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/utils/debug_print.dart'; import 'package:immich_mobile/utils/people.utils.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/person_sliver_app_bar.dart'; @RoutePage() @@ -51,6 +56,35 @@ class _DriftPersonPageState extends ConsumerState { } } + Future handleEditVisibility(BuildContext context) async { + final newIsHidden = !_person.isHidden; + + try { + final result = await ref.read(driftPeopleServiceProvider).updateVisibility(_person.id, newIsHidden); + + if (result != 0) { + ref.invalidate(driftGetAllPeopleProvider); + ContextHelper(context).pop(newIsHidden); + } + } catch (error) { + dPrint(() => 'Error updating visibility: $error'); + + if (!context.mounted) { + return; + } + + ImmichToast.show( + context: context, + msg: 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: ToastType.error, + ); + } + setState(() { + _person = _person.copyWith(isHidden: newIsHidden); + }); + } + Future showOptionSheet(BuildContext context) { return showModalBottomSheet( context: context, @@ -66,7 +100,12 @@ class _DriftPersonPageState extends ConsumerState { await handleEditBirthday(context); ContextHelper(context).pop(); }, + onEditVisibility: () async { + await handleEditVisibility(context); + ContextHelper(context).pop(); + }, birthdayExists: _person.birthDate != null, + isHidden: _person.isHidden, ); }, ); diff --git a/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart b/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart index 026a28bd7d..84b8c84431 100644 --- a/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/people/person_option_sheet.widget.dart @@ -2,11 +2,20 @@ import 'package:flutter/material.dart'; import 'package:immich_mobile/generated/translations.g.dart'; class PersonOptionSheet extends StatelessWidget { - const PersonOptionSheet({super.key, this.onEditName, this.onEditBirthday, this.birthdayExists = false}); + const PersonOptionSheet({ + super.key, + this.onEditName, + this.onEditBirthday, + this.onEditVisibility, + this.birthdayExists = false, + this.isHidden = false, + }); final VoidCallback? onEditName; final VoidCallback? onEditBirthday; + final VoidCallback? onEditVisibility; final bool birthdayExists; + final bool isHidden; @override Widget build(BuildContext context) { @@ -28,6 +37,11 @@ class PersonOptionSheet extends StatelessWidget { title: Text(birthdayExists ? context.t.edit_birthday : context.t.add_birthday, style: textStyle), onTap: onEditBirthday, ), + ListTile( + leading: Icon((isHidden ? Icons.visibility : Icons.visibility_off)), + title: Text((isHidden ? "unhide_person" : 'hide_person').t(context: context), style: textStyle), + onTap: onEditVisibility, + ), ], ), ), diff --git a/mobile/lib/repositories/person_api.repository.dart b/mobile/lib/repositories/person_api.repository.dart index 262868eea1..f761993070 100644 --- a/mobile/lib/repositories/person_api.repository.dart +++ b/mobile/lib/repositories/person_api.repository.dart @@ -11,11 +11,12 @@ class PersonApiRepository extends ApiRepository { PersonApiRepository(this._api); - Future update(String id, {String? name, DateTime? birthday}) async { + Future update(String id, {String? name, DateTime? birthday, bool? isHidden}) 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), birthDate: birthdayUtc == null ? const Optional.absent() : Optional.present(birthdayUtc), + isHidden: isHidden == null ? const Optional.absent() : Optional.present(isHidden), ); final response = await checkNull(_api.updatePerson(id, dto)); return _toPerson(response);