From 202082f62ee6ad4f9a4a8fb19e2c3b486ec7bf9e Mon Sep 17 00:00:00 2001 From: Fynn Petersen-Frey <10599762+fyfrey@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:50:21 +0200 Subject: [PATCH] refactor(mobile): use repositories in a number of services (#12891) * UserService * PartnerService * HashService * MemoryService * PersonService * SearchService * StackService --- mobile/analysis_options.yaml | 14 ++- mobile/lib/constants/constants.dart | 1 + mobile/lib/interfaces/asset.interface.dart | 5 ++ .../lib/interfaces/asset_api.interface.dart | 2 + .../lib/interfaces/partner_api.interface.dart | 13 +++ .../lib/interfaces/person_api.interface.dart | 22 +++++ mobile/lib/interfaces/user.interface.dart | 2 + mobile/lib/interfaces/user_api.interface.dart | 11 +++ .../models/search/search_filter.model.dart | 6 +- .../lib/pages/common/gallery_viewer.page.dart | 4 +- .../lib/pages/search/search_input.page.dart | 4 +- .../activity_service.provider.g.dart | Bin 938 -> 938 bytes .../activity_statistics.provider.g.dart | Bin 5904 -> 5904 bytes .../suggested_shared_users.provider.dart | 2 +- .../providers/map/map_state.provider.g.dart | Bin 933 -> 933 bytes .../lib/providers/search/people.provider.dart | 4 +- .../providers/search/people.provider.g.dart | Bin 8962 -> 8936 bytes mobile/lib/repositories/asset.repository.dart | 25 ++++++ .../repositories/asset_api.repository.dart | 31 ++++++- .../repositories/partner_api.repository.dart | 51 +++++++++++ .../repositories/person_api.repository.dart | 38 +++++++++ mobile/lib/repositories/user.repository.dart | 16 ++++ .../lib/repositories/user_api.repository.dart | 41 +++++++++ mobile/lib/services/background.service.dart | 19 +++-- mobile/lib/services/hash.service.dart | 29 +++---- mobile/lib/services/memory.service.dart | 13 ++- mobile/lib/services/partner.service.dart | 62 ++++++-------- mobile/lib/services/person.service.dart | 77 ++++++----------- mobile/lib/services/person.service.g.dart | Bin 907 -> 907 bytes mobile/lib/services/search.service.dart | 12 +-- mobile/lib/services/stack.service.dart | 15 ++-- mobile/lib/services/user.service.dart | 80 ++++++++---------- mobile/lib/utils/image_url_builder.dart | 4 +- .../widgets/asset_grid/thumbnail_image.dart | 4 +- .../search/search_filter/people_picker.dart | 8 +- 35 files changed, 409 insertions(+), 206 deletions(-) create mode 100644 mobile/lib/constants/constants.dart create mode 100644 mobile/lib/interfaces/partner_api.interface.dart create mode 100644 mobile/lib/interfaces/person_api.interface.dart create mode 100644 mobile/lib/interfaces/user_api.interface.dart create mode 100644 mobile/lib/repositories/partner_api.repository.dart create mode 100644 mobile/lib/repositories/person_api.repository.dart create mode 100644 mobile/lib/repositories/user_api.repository.dart diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index e996a54372..6a7d7a6b4d 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -69,14 +69,14 @@ custom_lint: - integration_test/test_utils/general_helper.dart - lib/main.dart - lib/routing/router.dart - - lib/utils/{db,image_url_builder,migration,renderlist_generator}.dart + - lib/utils/{db,migration,renderlist_generator}.dart - test/**.dart # refactor to make the providers and services testable - - lib/pages/common/{album_asset_selection,gallery_viewer}.page.dart + - lib/pages/common/album_asset_selection.page.dart - lib/providers/{archive,asset,authentication,db,favorite,partner,trash,user}.provider.dart - lib/providers/{album/album,album/shared_album,asset_viewer/asset_stack,asset_viewer/render_list,backup/backup,backup/manual_upload,search/all_motion_photos,search/recently_added_asset}.provider.dart - - lib/services/{asset,background,backup,hash,immich_logger,memory,partner,person,search,stack,sync,user}.service.dart - - lib/widgets/asset_grid/{asset_grid_data_structure,thumbnail_image}.dart + - lib/services/{asset,background,backup,immich_logger,sync}.service.dart + - lib/widgets/asset_grid/asset_grid_data_structure.dart - import_rule_openapi: message: openapi must only be used through ApiRepositories @@ -90,18 +90,16 @@ custom_lint: - test/modules/utils/openapi_patching_test.dart # filename is self-explanatory... # refactor - lib/models/map/map_marker.model.dart - - lib/models/search/search_filter.model.dart - lib/models/server_info/server_{config,disk_info,features,version}.model.dart - lib/models/shared_link/shared_link.model.dart - - lib/pages/search/search_input.page.dart - lib/providers/asset_viewer/asset_people.provider.dart - lib/providers/authentication.provider.dart - lib/providers/image/immich_remote_{image,thumbnail}_provider.dart - lib/providers/map/map_state.provider.dart - - lib/providers/search/{people,search,search_filter}.provider.dart + - lib/providers/search/{search,search_filter}.provider.dart - lib/providers/websocket.provider.dart - lib/routing/auth_guard.dart - - lib/services/{api,asset,backup,memory,oauth,partner,person,search,shared_link,stack,trash,user}.service.dart + - lib/services/{api,asset,backup,memory,oauth,search,shared_link,stack,trash}.service.dart - lib/widgets/album/album_thumbnail_listtile.dart - lib/widgets/forms/login/login_form.dart - lib/widgets/search/search_filter/{camera_picker,location_picker,people_picker}.dart diff --git a/mobile/lib/constants/constants.dart b/mobile/lib/constants/constants.dart new file mode 100644 index 0000000000..8b74b1a66f --- /dev/null +++ b/mobile/lib/constants/constants.dart @@ -0,0 +1 @@ +const int noDbId = -9223372036854775808; // from Isar diff --git a/mobile/lib/interfaces/asset.interface.dart b/mobile/lib/interfaces/asset.interface.dart index 98f4c7687c..0d2dcfa1b5 100644 --- a/mobile/lib/interfaces/asset.interface.dart +++ b/mobile/lib/interfaces/asset.interface.dart @@ -1,5 +1,6 @@ import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/entities/device_asset.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; abstract interface class IAssetRepository { @@ -12,6 +13,7 @@ abstract interface class IAssetRepository { bool? remote, int limit = 100, }); + Future> updateAll(List assets); Future> getMatches({ required List assets, @@ -19,4 +21,7 @@ abstract interface class IAssetRepository { bool? remote, int limit = 100, }); + + Future> getDeviceAssetsById(List ids); + Future upsertDeviceAssets(List deviceAssets); } diff --git a/mobile/lib/interfaces/asset_api.interface.dart b/mobile/lib/interfaces/asset_api.interface.dart index 201c85cea7..fe3320c9bb 100644 --- a/mobile/lib/interfaces/asset_api.interface.dart +++ b/mobile/lib/interfaces/asset_api.interface.dart @@ -13,4 +13,6 @@ abstract interface class IAssetApiRepository { }); // Future delete(String id); + + Future> search({List personIds = const []}); } diff --git a/mobile/lib/interfaces/partner_api.interface.dart b/mobile/lib/interfaces/partner_api.interface.dart new file mode 100644 index 0000000000..bca1baf66d --- /dev/null +++ b/mobile/lib/interfaces/partner_api.interface.dart @@ -0,0 +1,13 @@ +import 'package:immich_mobile/entities/user.entity.dart'; + +abstract interface class IPartnerApiRepository { + Future> getAll(Direction direction); + Future create(String id); + Future update(String id, {required bool inTimeline}); + Future delete(String id); +} + +enum Direction { + sharedWithMe, + sharedByMe, +} diff --git a/mobile/lib/interfaces/person_api.interface.dart b/mobile/lib/interfaces/person_api.interface.dart new file mode 100644 index 0000000000..b2fa28df8c --- /dev/null +++ b/mobile/lib/interfaces/person_api.interface.dart @@ -0,0 +1,22 @@ +abstract interface class IPersonApiRepository { + Future> getAll(); + Future update(String id, {String? name}); +} + +class Person { + Person({ + required this.id, + required this.isHidden, + required this.name, + required this.thumbnailPath, + this.birthDate, + this.updatedAt, + }); + + final String id; + final DateTime? birthDate; + final bool isHidden; + final String name; + final String thumbnailPath; + final DateTime? updatedAt; +} diff --git a/mobile/lib/interfaces/user.interface.dart b/mobile/lib/interfaces/user.interface.dart index 4e847ea022..828a7b2398 100644 --- a/mobile/lib/interfaces/user.interface.dart +++ b/mobile/lib/interfaces/user.interface.dart @@ -3,4 +3,6 @@ import 'package:immich_mobile/entities/user.entity.dart'; abstract interface class IUserRepository { Future> getByIds(List ids); Future get(String id); + Future> getAll({bool self = true}); + Future update(User user); } diff --git a/mobile/lib/interfaces/user_api.interface.dart b/mobile/lib/interfaces/user_api.interface.dart new file mode 100644 index 0000000000..67ac3c0883 --- /dev/null +++ b/mobile/lib/interfaces/user_api.interface.dart @@ -0,0 +1,11 @@ +import 'dart:typed_data'; + +import 'package:immich_mobile/entities/user.entity.dart'; + +abstract interface class IUserApiRepository { + Future> getAll(); + Future<({String profileImagePath})> createProfileImage({ + required String name, + required Uint8List data, + }); +} diff --git a/mobile/lib/models/search/search_filter.model.dart b/mobile/lib/models/search/search_filter.model.dart index 6a7c612b15..297a819b6a 100644 --- a/mobile/lib/models/search/search_filter.model.dart +++ b/mobile/lib/models/search/search_filter.model.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:openapi/api.dart'; +import 'package:immich_mobile/interfaces/person_api.interface.dart'; class SearchLocationFilter { String? country; @@ -235,7 +235,7 @@ class SearchDisplayFilters { class SearchFilter { String? context; String? filename; - Set people; + Set people; SearchLocationFilter location; SearchCameraFilter camera; SearchDateFilter date; @@ -258,7 +258,7 @@ class SearchFilter { SearchFilter copyWith({ String? context, String? filename, - Set? people, + Set? people, SearchLocationFilter? location, SearchCameraFilter? camera, SearchDateFilter? date, diff --git a/mobile/lib/pages/common/gallery_viewer.page.dart b/mobile/lib/pages/common/gallery_viewer.page.dart index d8ea7cd89b..1434d1cca5 100644 --- a/mobile/lib/pages/common/gallery_viewer.page.dart +++ b/mobile/lib/pages/common/gallery_viewer.page.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart' hide Store; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/pages/common/video_viewer.page.dart'; @@ -30,7 +31,6 @@ import 'package:immich_mobile/widgets/photo_view/photo_view_gallery.dart'; import 'package:immich_mobile/widgets/photo_view/src/photo_view_computed_scale.dart'; import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart'; import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attributes.dart'; -import 'package:isar/isar.dart'; @RoutePage() // ignore: must_be_immutable @@ -73,7 +73,7 @@ class GalleryViewerPage extends HookConsumerWidget { : []; final stackElements = showStack ? [currentAsset, ...stack] : []; // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id - final isFromDto = currentAsset.id == Isar.autoIncrement; + final isFromDto = currentAsset.id == noDbId; Asset asset = stackIndex.value == -1 ? currentAsset diff --git a/mobile/lib/pages/search/search_input.page.dart b/mobile/lib/pages/search/search_input.page.dart index acabc75aa4..2ca2a37918 100644 --- a/mobile/lib/pages/search/search_input.page.dart +++ b/mobile/lib/pages/search/search_input.page.dart @@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; +import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/providers/search/paginated_search.provider.dart'; import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart'; @@ -19,7 +20,6 @@ import 'package:immich_mobile/widgets/search/search_filter/media_type_picker.dar import 'package:immich_mobile/widgets/search/search_filter/people_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_chip.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_utils.dart'; -import 'package:openapi/api.dart'; @RoutePage() class SearchInputPage extends HookConsumerWidget { @@ -110,7 +110,7 @@ class SearchInputPage extends HookConsumerWidget { } showPeoplePicker() { - handleOnSelect(Set value) { + handleOnSelect(Set value) { filter.value = filter.value.copyWith( people: value, ); diff --git a/mobile/lib/providers/activity_service.provider.g.dart b/mobile/lib/providers/activity_service.provider.g.dart index 8e5ef43260119430d4045c3d14a203ea90da9b28..d42b2a39e45f7850e001a6d3679218ef41228e28 100644 GIT binary patch delta 51 zcmZ3*zKVT=4x^fpaiVc*s(DJ1xuKc4S&EUlp=C;9qM3=2p?RX2g>iDSX|j20;^rX6 G2qpk{9u7|c delta 51 zcmZ3*zKVT=4x^fBN{Wf4scDL#Nt$U=nt@@mfkBFSnuWQkL5hKSs(E5^s(Es<$>t!& G2qpk~qYi)o diff --git a/mobile/lib/providers/activity_statistics.provider.g.dart b/mobile/lib/providers/activity_statistics.provider.g.dart index 79856c525b77cb689ba45a0663137a66a62605ce..16a3c0e81b3748fb7f1478ce7d8a4dffafe4d172 100644 GIT binary patch delta 53 zcmbQBH$iWM8KZ__nu&3mK~i#(p<%MQsY!C8adMKWg;}DZv8lO1N|KSOfst{NWunFA IIL1w)0HA~qI{*Lx delta 53 zcmbQBH$iWM8KXv`X_|RbQfjK9g{5J#v2l{Qk)@$!qOnP;nXyrFqGf8DWpau|N>bY9 IIL1w)0IXdQBme*a diff --git a/mobile/lib/providers/album/suggested_shared_users.provider.dart b/mobile/lib/providers/album/suggested_shared_users.provider.dart index 77518f47d0..fe8a1fccce 100644 --- a/mobile/lib/providers/album/suggested_shared_users.provider.dart +++ b/mobile/lib/providers/album/suggested_shared_users.provider.dart @@ -5,5 +5,5 @@ import 'package:immich_mobile/services/user.service.dart'; final otherUsersProvider = FutureProvider.autoDispose>((ref) { UserService userService = ref.watch(userServiceProvider); - return userService.getUsersInDb(); + return userService.getUsers(); }); diff --git a/mobile/lib/providers/map/map_state.provider.g.dart b/mobile/lib/providers/map/map_state.provider.g.dart index eff7b4b68e60f4fc361b714f016a64a2528017ff..23a570d1c8789f532cb1de51e8cddb0ecfcc5e67 100644 GIT binary patch delta 53 zcmZ3=zLb4~8l#4hQL0I*skvcNih;SYK}u4xu}PAlfu)hDX`-1?lBJPBs%5fyikaDF IKgMt-0Ej6LH~;_u delta 53 zcmZ3=zLb4~8l#4>VOnBZs-byeqJ?R)iG{JbWulQ$YKn16l5ujfrAcC%sbzAiX_Cce IKgMt-0HgsAYXATM diff --git a/mobile/lib/providers/search/people.provider.dart b/mobile/lib/providers/search/people.provider.dart index e2c243354b..7c956f0a37 100644 --- a/mobile/lib/providers/search/people.provider.dart +++ b/mobile/lib/providers/search/people.provider.dart @@ -1,14 +1,14 @@ +import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/services/person.service.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; -import 'package:openapi/api.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'people.provider.g.dart'; @riverpod -Future> getAllPeople( +Future> getAllPeople( GetAllPeopleRef ref, ) async { final PersonService personService = ref.read(personServiceProvider); diff --git a/mobile/lib/providers/search/people.provider.g.dart b/mobile/lib/providers/search/people.provider.g.dart index db2edfb9567aaa4944207ecef90be33ff5cbd00a..c5ff6287cd7a82ad1bebd40ae98267e79394634f 100644 GIT binary patch delta 69 zcmZp2d*Ql4o>AS{#Lzs+Jk=oC$k5Q(!YIYW#KIua#LzU=*wo0-*wWI{G{w|B$!xM4 ZW8`E(IjPBe8F@BeVbo&W%*p&y9sr#*6HWjC delta 98 zcmaFi+T^xDo>AQ-H7(5y2$E7w6U|M`4GmHZQ!Pv_%u@{vQ!ETkO^kse7N$v)-54WT oxD*r=CLa)#n!J;dhdU^>xFA2TIMt;jfAdjBEk+c9_e?+K0gqiC{Qv*} diff --git a/mobile/lib/repositories/asset.repository.dart b/mobile/lib/repositories/asset.repository.dart index c6012af371..087344302a 100644 --- a/mobile/lib/repositories/asset.repository.dart +++ b/mobile/lib/repositories/asset.repository.dart @@ -1,6 +1,11 @@ +import 'dart:io'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/album.entity.dart'; +import 'package:immich_mobile/entities/android_device_asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/entities/device_asset.entity.dart'; +import 'package:immich_mobile/entities/ios_device_asset.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/providers/db.provider.dart'; @@ -69,6 +74,12 @@ class AssetRepository implements IAssetRepository { return query.limit(limit).findAll(); } + @override + Future> updateAll(List assets) async { + await _db.writeTxn(() => _db.assets.putAll(assets)); + return assets; + } + @override Future> getMatches({ required List assets, @@ -86,6 +97,20 @@ class AssetRepository implements IAssetRepository { } return _getMatchesImpl(query, ownerId, assets, limit); } + + @override + Future> getDeviceAssetsById(List ids) => + Platform.isAndroid + ? _db.androidDeviceAssets.getAll(ids.cast()) + : _db.iOSDeviceAssets.getAllById(ids.cast()); + + @override + Future upsertDeviceAssets(List deviceAssets) => + _db.writeTxn( + () => Platform.isAndroid + ? _db.androidDeviceAssets.putAll(deviceAssets.cast()) + : _db.iOSDeviceAssets.putAll(deviceAssets.cast()), + ); } Future> _getMatchesImpl( diff --git a/mobile/lib/repositories/asset_api.repository.dart b/mobile/lib/repositories/asset_api.repository.dart index 3ad0e1cba0..eb796f6c6b 100644 --- a/mobile/lib/repositories/asset_api.repository.dart +++ b/mobile/lib/repositories/asset_api.repository.dart @@ -6,14 +6,18 @@ import 'package:immich_mobile/repositories/base_api.repository.dart'; import 'package:openapi/api.dart'; final assetApiRepositoryProvider = Provider( - (ref) => AssetApiRepository(ref.watch(apiServiceProvider).assetsApi), + (ref) => AssetApiRepository( + ref.watch(apiServiceProvider).assetsApi, + ref.watch(apiServiceProvider).searchApi, + ), ); class AssetApiRepository extends BaseApiRepository implements IAssetApiRepository { final AssetsApi _api; + final SearchApi _searchApi; - AssetApiRepository(this._api); + AssetApiRepository(this._api, this._searchApi); @override Future update(String id, {String? description}) async { @@ -22,4 +26,27 @@ class AssetApiRepository extends BaseApiRepository ); return Asset.remote(response); } + + @override + Future> search({List personIds = const []}) async { + // TODO this always fetches all assets, change API and usage to actually do pagination + final List result = []; + bool hasNext = true; + int currentPage = 1; + while (hasNext) { + final response = await checkNull( + _searchApi.searchMetadata( + MetadataSearchDto( + personIds: personIds, + page: currentPage, + size: 1000, + ), + ), + ); + result.addAll(response.assets.items.map(Asset.remote)); + hasNext = response.assets.nextPage != null; + currentPage++; + } + return result; + } } diff --git a/mobile/lib/repositories/partner_api.repository.dart b/mobile/lib/repositories/partner_api.repository.dart new file mode 100644 index 0000000000..3419a2bc77 --- /dev/null +++ b/mobile/lib/repositories/partner_api.repository.dart @@ -0,0 +1,51 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/user.entity.dart'; +import 'package:immich_mobile/interfaces/partner_api.interface.dart'; +import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/repositories/base_api.repository.dart'; +import 'package:openapi/api.dart'; + +final partnerApiRepositoryProvider = Provider( + (ref) => PartnerApiRepository( + ref.watch(apiServiceProvider).partnersApi, + ), +); + +class PartnerApiRepository extends BaseApiRepository + implements IPartnerApiRepository { + final PartnersApi _api; + + PartnerApiRepository(this._api); + + @override + Future> getAll(Direction direction) async { + final response = await checkNull( + _api.getPartners( + direction == Direction.sharedByMe + ? PartnerDirection.by + : PartnerDirection.with_, + ), + ); + return response.map(User.fromPartnerDto).toList(); + } + + @override + Future create(String id) async { + final dto = await checkNull(_api.createPartner(id)); + return User.fromPartnerDto(dto); + } + + @override + Future delete(String id) => checkNull(_api.removePartner(id)); + + @override + Future update(String id, {required bool inTimeline}) async { + final dto = await checkNull( + _api.updatePartner( + id, + UpdatePartnerDto(inTimeline: inTimeline), + ), + ); + return User.fromPartnerDto(dto); + } +} diff --git a/mobile/lib/repositories/person_api.repository.dart b/mobile/lib/repositories/person_api.repository.dart new file mode 100644 index 0000000000..8071c33dc2 --- /dev/null +++ b/mobile/lib/repositories/person_api.repository.dart @@ -0,0 +1,38 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/interfaces/person_api.interface.dart'; +import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/repositories/base_api.repository.dart'; +import 'package:openapi/api.dart'; + +final personApiRepositoryProvider = Provider( + (ref) => PersonApiRepository(ref.watch(apiServiceProvider).peopleApi), +); + +class PersonApiRepository extends BaseApiRepository + implements IPersonApiRepository { + final PeopleApi _api; + + PersonApiRepository(this._api); + + @override + Future> getAll() async { + final dto = await checkNull(_api.getAllPeople()); + return dto.people.map(_toPerson).toList(); + } + + @override + Future update(String id, {String? name}) async { + final dto = await checkNull( + _api.updatePerson(id, PersonUpdateDto(name: name)), + ); + return _toPerson(dto); + } + + static Person _toPerson(PersonResponseDto dto) => Person( + birthDate: dto.birthDate, + id: dto.id, + isHidden: dto.isHidden, + name: dto.name, + thumbnailPath: dto.thumbnailPath, + ); +} diff --git a/mobile/lib/repositories/user.repository.dart b/mobile/lib/repositories/user.repository.dart index b05af9a57f..796b1f421b 100644 --- a/mobile/lib/repositories/user.repository.dart +++ b/mobile/lib/repositories/user.repository.dart @@ -1,4 +1,5 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/interfaces/user.interface.dart'; import 'package:immich_mobile/providers/db.provider.dart'; @@ -20,4 +21,19 @@ class UserRepository implements IUserRepository { @override Future get(String id) => _db.users.getById(id); + + @override + Future> getAll({bool self = true}) { + if (self) { + return _db.users.where().findAll(); + } + final int userId = Store.get(StoreKey.currentUser).isarId; + return _db.users.where().isarIdNotEqualTo(userId).findAll(); + } + + @override + Future update(User user) async { + await _db.writeTxn(() => _db.users.put(user)); + return user; + } } diff --git a/mobile/lib/repositories/user_api.repository.dart b/mobile/lib/repositories/user_api.repository.dart new file mode 100644 index 0000000000..ffc50ae4c3 --- /dev/null +++ b/mobile/lib/repositories/user_api.repository.dart @@ -0,0 +1,41 @@ +import 'dart:typed_data'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:http/http.dart'; +import 'package:immich_mobile/entities/user.entity.dart'; +import 'package:immich_mobile/interfaces/user_api.interface.dart'; +import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/repositories/base_api.repository.dart'; +import 'package:openapi/api.dart'; + +final userApiRepositoryProvider = Provider( + (ref) => UserApiRepository( + ref.watch(apiServiceProvider).usersApi, + ), +); + +class UserApiRepository extends BaseApiRepository + implements IUserApiRepository { + final UsersApi _api; + + UserApiRepository(this._api); + + @override + Future> getAll() async { + final dto = await checkNull(_api.searchUsers()); + return dto.map(User.fromSimpleUserDto).toList(); + } + + @override + Future<({String profileImagePath})> createProfileImage({ + required String name, + required Uint8List data, + }) async { + final response = await checkNull( + _api.createProfileImage( + MultipartFile.fromBytes('file', data, filename: name), + ), + ); + return (profileImagePath: response.profileImagePath); + } +} diff --git a/mobile/lib/services/background.service.dart b/mobile/lib/services/background.service.dart index 09030a621b..d06bc86d48 100644 --- a/mobile/lib/services/background.service.dart +++ b/mobile/lib/services/background.service.dart @@ -18,7 +18,9 @@ import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/repositories/backup.repository.dart'; import 'package:immich_mobile/repositories/album_media.repository.dart'; import 'package:immich_mobile/repositories/file_media.repository.dart'; +import 'package:immich_mobile/repositories/partner_api.repository.dart'; import 'package:immich_mobile/repositories/user.repository.dart'; +import 'package:immich_mobile/repositories/user_api.repository.dart'; import 'package:immich_mobile/services/album.service.dart'; import 'package:immich_mobile/services/entity.service.dart'; import 'package:immich_mobile/services/hash.service.dart'; @@ -30,7 +32,6 @@ import 'package:immich_mobile/services/backup.service.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:immich_mobile/services/partner.service.dart'; import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/services/user.service.dart'; import 'package:immich_mobile/utils/backup_progress.dart'; @@ -362,16 +363,20 @@ class BackgroundService { apiService.setAccessToken(Store.get(StoreKey.accessToken)); AppSettingsService settingService = AppSettingsService(); AppSettingsService settingsService = AppSettingsService(); - PartnerService partnerService = PartnerService(apiService, db); AlbumRepository albumRepository = AlbumRepository(db); AssetRepository assetRepository = AssetRepository(db); BackupRepository backupAlbumRepository = BackupRepository(db); AlbumMediaRepository albumMediaRepository = AlbumMediaRepository(); FileMediaRepository fileMediaRepository = FileMediaRepository(); UserRepository userRepository = UserRepository(db); + UserApiRepository userApiRepository = + UserApiRepository(apiService.usersApi); AlbumApiRepository albumApiRepository = AlbumApiRepository(apiService.albumsApi); - HashService hashService = HashService(db, this, albumMediaRepository); + PartnerApiRepository partnerApiRepository = + PartnerApiRepository(apiService.partnersApi); + HashService hashService = + HashService(assetRepository, this, albumMediaRepository); EntityService entityService = EntityService(assetRepository, userRepository); SyncService syncSerive = SyncService( @@ -381,8 +386,12 @@ class BackgroundService { albumMediaRepository, albumApiRepository, ); - UserService userService = - UserService(apiService, db, syncSerive, partnerService); + UserService userService = UserService( + partnerApiRepository, + userApiRepository, + userRepository, + syncSerive, + ); AlbumService albumService = AlbumService( userService, syncSerive, diff --git a/mobile/lib/services/hash.service.dart b/mobile/lib/services/hash.service.dart index 94d680972f..3827e421e6 100644 --- a/mobile/lib/services/hash.service.dart +++ b/mobile/lib/services/hash.service.dart @@ -4,20 +4,24 @@ import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/interfaces/album_media.interface.dart'; +import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/repositories/album_media.repository.dart'; +import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/services/background.service.dart'; import 'package:immich_mobile/entities/android_device_asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/device_asset.entity.dart'; import 'package:immich_mobile/entities/ios_device_asset.entity.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/extensions/string_extensions.dart'; -import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; class HashService { - HashService(this._db, this._backgroundService, this._albumMediaRepository); - final Isar _db; + HashService( + this._assetRepository, + this._backgroundService, + this._albumMediaRepository, + ); + final IAssetRepository _assetRepository; final BackgroundService _backgroundService; final IAlbumMediaRepository _albumMediaRepository; final _log = Logger('HashService'); @@ -55,7 +59,8 @@ class HashService { final ids = assets .map(Platform.isAndroid ? (a) => a.localId!.toInt() : (a) => a.localId!) .toList(); - final List hashes = await _lookupHashes(ids); + final List hashes = + await _assetRepository.getDeviceAssetsById(ids); final List toAdd = []; final List toHash = []; @@ -106,12 +111,6 @@ class HashService { return _getHashedAssets(assets, hashes); } - /// Lookup hashes of assets by their local ID - Future> _lookupHashes(List ids) => - Platform.isAndroid - ? _db.androidDeviceAssets.getAll(ids.cast()) - : _db.iOSDeviceAssets.getAllById(ids.cast()); - /// Processes a batch of files and saves any successfully hashed /// values to the DB table. Future _processBatch( @@ -131,11 +130,7 @@ class HashService { final validHashes = anyNull ? toAdd.where((e) => e.hash.length == 20).toList(growable: false) : toAdd; - await _db.writeTxn( - () => Platform.isAndroid - ? _db.androidDeviceAssets.putAll(validHashes.cast()) - : _db.iOSDeviceAssets.putAll(validHashes.cast()), - ); + await _assetRepository.upsertDeviceAssets(validHashes); _log.fine("Hashed ${validHashes.length}/${toHash.length} assets"); } @@ -168,7 +163,7 @@ class HashService { final hashServiceProvider = Provider( (ref) => HashService( - ref.watch(dbProvider), + ref.watch(assetRepositoryProvider), ref.watch(backgroundServiceProvider), ref.watch(albumMediaRepositoryProvider), ), diff --git a/mobile/lib/services/memory.service.dart b/mobile/lib/services/memory.service.dart index ea07f7c019..b95899df67 100644 --- a/mobile/lib/services/memory.service.dart +++ b/mobile/lib/services/memory.service.dart @@ -1,18 +1,17 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/models/memories/memory.model.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; +import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; final memoryServiceProvider = StateProvider((ref) { return MemoryService( ref.watch(apiServiceProvider), - ref.watch(dbProvider), + ref.watch(assetRepositoryProvider), ); }); @@ -20,9 +19,9 @@ class MemoryService { final log = Logger("MemoryService"); final ApiService _apiService; - final Isar _db; + final IAssetRepository _assetRepository; - MemoryService(this._apiService, this._db); + MemoryService(this._apiService, this._assetRepository); Future?> getMemoryLane() async { try { @@ -39,7 +38,7 @@ class MemoryService { List memories = []; for (final MemoryLaneResponseDto(:yearsAgo, :assets) in data) { final dbAssets = - await _db.assets.getAllByRemoteId(assets.map((e) => e.id)); + await _assetRepository.getAllByRemoteId(assets.map((e) => e.id)); if (dbAssets.isNotEmpty) { final String title = yearsAgo <= 1 ? 'memories_year_ago'.tr() diff --git a/mobile/lib/services/partner.service.dart b/mobile/lib/services/partner.service.dart index 8cd2fe424f..67d7f4e1d1 100644 --- a/mobile/lib/services/partner.service.dart +++ b/mobile/lib/services/partner.service.dart @@ -1,43 +1,33 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/user.entity.dart'; -import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; -import 'package:immich_mobile/services/api.service.dart'; -import 'package:isar/isar.dart'; +import 'package:immich_mobile/interfaces/partner_api.interface.dart'; +import 'package:immich_mobile/interfaces/user.interface.dart'; +import 'package:immich_mobile/repositories/partner_api.repository.dart'; +import 'package:immich_mobile/repositories/user.repository.dart'; import 'package:logging/logging.dart'; -import 'package:openapi/api.dart'; final partnerServiceProvider = Provider( (ref) => PartnerService( - ref.watch(apiServiceProvider), - ref.watch(dbProvider), + ref.watch(partnerApiRepositoryProvider), + ref.watch(userRepositoryProvider), ), ); class PartnerService { - final ApiService _apiService; - final Isar _db; + final IPartnerApiRepository _partnerApiRepository; + final IUserRepository _userRepository; final Logger _log = Logger("PartnerService"); - PartnerService(this._apiService, this._db); - - Future?> getPartners(PartnerDirection direction) async { - try { - final userDtos = await _apiService.partnersApi.getPartners(direction); - if (userDtos != null) { - return userDtos.map((u) => User.fromPartnerDto(u)).toList(); - } - } catch (e) { - _log.warning("Failed to get partners for direction $direction", e); - } - return null; - } + PartnerService( + this._partnerApiRepository, + this._userRepository, + ); Future removePartner(User partner) async { try { - await _apiService.partnersApi.removePartner(partner.id); + await _partnerApiRepository.delete(partner.id); partner.isPartnerSharedBy = false; - await _db.writeTxn(() => _db.users.put(partner)); + await _userRepository.update(partner); } catch (e) { _log.warning("Failed to remove partner ${partner.id}", e); return false; @@ -47,12 +37,10 @@ class PartnerService { Future addPartner(User partner) async { try { - final dto = await _apiService.partnersApi.createPartner(partner.id); - if (dto != null) { - partner.isPartnerSharedBy = true; - await _db.writeTxn(() => _db.users.put(partner)); - return true; - } + await _partnerApiRepository.create(partner.id); + partner.isPartnerSharedBy = true; + await _userRepository.update(partner); + return true; } catch (e) { _log.warning("Failed to add partner ${partner.id}", e); } @@ -61,13 +49,13 @@ class PartnerService { Future updatePartner(User partner, {required bool inTimeline}) async { try { - final dto = await _apiService.partnersApi - .updatePartner(partner.id, UpdatePartnerDto(inTimeline: inTimeline)); - if (dto != null) { - partner.inTimeline = dto.inTimeline ?? partner.inTimeline; - await _db.writeTxn(() => _db.users.put(partner)); - return true; - } + final dto = await _partnerApiRepository.update( + partner.id, + inTimeline: inTimeline, + ); + partner.inTimeline = dto.inTimeline; + await _userRepository.update(partner); + return true; } catch (e) { _log.warning("Failed to update partner ${partner.id}", e); } diff --git a/mobile/lib/services/person.service.dart b/mobile/lib/services/person.service.dart index ddb61f5e48..5b325acdc5 100644 --- a/mobile/lib/services/person.service.dart +++ b/mobile/lib/services/person.service.dart @@ -1,29 +1,37 @@ import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; -import 'package:immich_mobile/services/api.service.dart'; -import 'package:isar/isar.dart'; +import 'package:immich_mobile/interfaces/asset.interface.dart'; +import 'package:immich_mobile/interfaces/asset_api.interface.dart'; +import 'package:immich_mobile/interfaces/person_api.interface.dart'; +import 'package:immich_mobile/repositories/asset.repository.dart'; +import 'package:immich_mobile/repositories/asset_api.repository.dart'; +import 'package:immich_mobile/repositories/person_api.repository.dart'; import 'package:logging/logging.dart'; -import 'package:openapi/api.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'person.service.g.dart'; @riverpod -PersonService personService(PersonServiceRef ref) => - PersonService(ref.read(apiServiceProvider), ref.read(dbProvider)); +PersonService personService(PersonServiceRef ref) => PersonService( + ref.watch(personApiRepositoryProvider), + ref.watch(assetApiRepositoryProvider), + ref.read(assetRepositoryProvider), + ); class PersonService { final Logger _log = Logger("PersonService"); - final ApiService _apiService; - final Isar _db; + final IPersonApiRepository _personApiRepository; + final IAssetApiRepository _assetApiRepository; + final IAssetRepository _assetRepository; - PersonService(this._apiService, this._db); + PersonService( + this._personApiRepository, + this._assetApiRepository, + this._assetRepository, + ); - Future> getAllPeople() async { + Future> getAllPeople() async { try { - final peopleResponseDto = await _apiService.peopleApi.getAllPeople(); - return peopleResponseDto?.people ?? []; + return await _personApiRepository.getAll(); } catch (error, stack) { _log.severe("Error while fetching curated people", error, stack); return []; @@ -31,50 +39,19 @@ class PersonService { } Future> getPersonAssets(String id) async { - List result = []; - var hasNext = true; - var currentPage = 1; - try { - while (hasNext) { - final response = await _apiService.searchApi.searchMetadata( - MetadataSearchDto( - personIds: [id], - page: currentPage, - size: 1000, - ), - ); - - if (response == null) { - break; - } - - if (response.assets.nextPage == null) { - hasNext = false; - } - - final assets = response.assets.items; - final mapAssets = - await _db.assets.getAllByRemoteId(assets.map((e) => e.id)); - result.addAll(mapAssets); - - currentPage++; - } + final assets = await _assetApiRepository.search(personIds: [id]); + return await _assetRepository + .getAllByRemoteId(assets.map((a) => a.remoteId!)); } catch (error, stack) { _log.severe("Error while fetching person assets", error, stack); } - - return result; + return []; } - Future updateName(String id, String name) async { + Future updateName(String id, String name) async { try { - return await _apiService.peopleApi.updatePerson( - id, - PersonUpdateDto( - name: name, - ), - ); + return await _personApiRepository.update(id, name: name); } catch (error, stack) { _log.severe("Error while updating person name", error, stack); } diff --git a/mobile/lib/services/person.service.g.dart b/mobile/lib/services/person.service.g.dart index 01a5ed8f309434afa387cbb946ebe1514667207f..9a24069fbffa5cd514f77fd7d0a2c6401ce39fe6 100644 GIT binary patch delta 53 zcmeBX?`Gd1&!}N+lxAd+oMf74oRVr_YHFNpXl`O+o@#8IXpowgl4@>ZV3}xQoSL%P IozaB}0EUYWb^rhX delta 53 zcmeBX?`Gd1&!}N)l4_QcW|Cx)nwn^CVv=T-l4@XJnPy>ZXqs%9mTG2XY>;MVZfUXE IozaB}0FvJhZvX%Q diff --git a/mobile/lib/services/search.service.dart b/mobile/lib/services/search.service.dart index cf3905e5ca..336fe45010 100644 --- a/mobile/lib/services/search.service.dart +++ b/mobile/lib/services/search.service.dart @@ -1,27 +1,27 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; +import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; final searchServiceProvider = Provider( (ref) => SearchService( ref.watch(apiServiceProvider), - ref.watch(dbProvider), + ref.watch(assetRepositoryProvider), ), ); class SearchService { final ApiService _apiService; - final Isar _db; + final IAssetRepository _assetRepository; final _log = Logger("SearchService"); - SearchService(this._apiService, this._db); + SearchService(this._apiService, this._assetRepository); Future?> getSearchSuggestions( SearchSuggestionType type, { @@ -103,7 +103,7 @@ class SearchService { return null; } - return _db.assets + return _assetRepository .getAllByRemoteId(response.assets.items.map((e) => e.id)); } catch (error, stackTrace) { _log.severe("Failed to search for assets", error, stackTrace); diff --git a/mobile/lib/services/stack.service.dart b/mobile/lib/services/stack.service.dart index 75074101c2..8bff21fef6 100644 --- a/mobile/lib/services/stack.service.dart +++ b/mobile/lib/services/stack.service.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; +import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:isar/isar.dart'; import 'package:openapi/api.dart'; class StackService { - StackService(this._api, this._db); + StackService(this._api, this._assetRepository); final ApiService _api; - final Isar _db; + final IAssetRepository _assetRepository; Future getStack(String stackId) async { try { @@ -61,10 +61,7 @@ class StackService { removeAssets.add(asset); } - - _db.writeTxn(() async { - await _db.assets.putAll(removeAssets); - }); + await _assetRepository.updateAll(removeAssets); } catch (error) { debugPrint("Error while deleting stack: $error"); } @@ -74,6 +71,6 @@ class StackService { final stackServiceProvider = Provider( (ref) => StackService( ref.watch(apiServiceProvider), - ref.watch(dbProvider), + ref.watch(assetRepositoryProvider), ), ); diff --git a/mobile/lib/services/user.service.dart b/mobile/lib/services/user.service.dart index 9631141c41..4c2b3cbbd0 100644 --- a/mobile/lib/services/user.service.dart +++ b/mobile/lib/services/user.service.dart @@ -1,68 +1,48 @@ import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:http/http.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:immich_mobile/services/partner.service.dart'; -import 'package:immich_mobile/entities/store.entity.dart'; +import 'package:immich_mobile/interfaces/partner_api.interface.dart'; +import 'package:immich_mobile/interfaces/user.interface.dart'; +import 'package:immich_mobile/interfaces/user_api.interface.dart'; +import 'package:immich_mobile/repositories/partner_api.repository.dart'; +import 'package:immich_mobile/repositories/user.repository.dart'; +import 'package:immich_mobile/repositories/user_api.repository.dart'; import 'package:immich_mobile/entities/user.entity.dart'; -import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/db.provider.dart'; -import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/utils/diff.dart'; -import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; -import 'package:openapi/api.dart'; final userServiceProvider = Provider( (ref) => UserService( - ref.watch(apiServiceProvider), - ref.watch(dbProvider), + ref.watch(partnerApiRepositoryProvider), + ref.watch(userApiRepositoryProvider), + ref.watch(userRepositoryProvider), ref.watch(syncServiceProvider), - ref.watch(partnerServiceProvider), ), ); class UserService { - final ApiService _apiService; - final Isar _db; + final IPartnerApiRepository _partnerApiRepository; + final IUserApiRepository _userApiRepository; + final IUserRepository _userRepository; final SyncService _syncService; - final PartnerService _partnerService; final Logger _log = Logger("UserService"); UserService( - this._apiService, - this._db, + this._partnerApiRepository, + this._userApiRepository, + this._userRepository, this._syncService, - this._partnerService, ); - Future?> _getAllUsers() async { - try { - final dto = await _apiService.usersApi.searchUsers(); - return dto?.map(User.fromSimpleUserDto).toList(); - } catch (e) { - _log.warning("Failed get all users", e); - return null; - } - } + Future> getUsers({bool self = false}) => + _userRepository.getAll(self: self); - Future> getUsersInDb({bool self = false}) async { - if (self) { - return _db.users.where().findAll(); - } - final int userId = Store.get(StoreKey.currentUser).isarId; - return _db.users.where().isarIdNotEqualTo(userId).findAll(); - } - - Future uploadProfileImage(XFile image) async { + Future<({String profileImagePath})?> uploadProfileImage(XFile image) async { try { - return await _apiService.usersApi.createProfileImage( - MultipartFile.fromBytes( - 'file', - await image.readAsBytes(), - filename: image.name, - ), + return await _userApiRepository.createProfileImage( + name: image.name, + data: await image.readAsBytes(), ); } catch (e) { _log.warning("Failed to upload profile image", e); @@ -71,13 +51,19 @@ class UserService { } Future?> getUsersFromServer() async { - final List? users = await _getAllUsers(); - final List? sharedBy = - await _partnerService.getPartners(PartnerDirection.by); - final List? sharedWith = - await _partnerService.getPartners(PartnerDirection.with_); + List? users; + try { + users = await _userApiRepository.getAll(); + } catch (e) { + _log.warning("Failed to fetch users", e); + users = null; + } + final List sharedBy = + await _partnerApiRepository.getAll(Direction.sharedByMe); + final List sharedWith = + await _partnerApiRepository.getAll(Direction.sharedWithMe); - if (users == null || sharedBy == null || sharedWith == null) { + if (users == null) { _log.warning("Failed to refresh users"); return null; } diff --git a/mobile/lib/utils/image_url_builder.dart b/mobile/lib/utils/image_url_builder.dart index e7a1b9e39e..9fc7b13eed 100644 --- a/mobile/lib/utils/image_url_builder.dart +++ b/mobile/lib/utils/image_url_builder.dart @@ -1,7 +1,7 @@ +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; -import 'package:isar/isar.dart'; import 'package:openapi/api.dart'; String getThumbnailUrl( @@ -61,7 +61,7 @@ String getOriginalUrlForRemoteId(final String id) { String getImageCacheKey(final Asset asset) { // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id - final isFromDto = asset.id == Isar.autoIncrement; + final isFromDto = asset.id == noDbId; return '${isFromDto ? asset.remoteId : asset.id}_fullStage'; } diff --git a/mobile/lib/widgets/asset_grid/thumbnail_image.dart b/mobile/lib/widgets/asset_grid/thumbnail_image.dart index 8e818f64fb..6cadef763d 100644 --- a/mobile/lib/widgets/asset_grid/thumbnail_image.dart +++ b/mobile/lib/widgets/asset_grid/thumbnail_image.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; import 'package:immich_mobile/utils/storage_indicator.dart'; -import 'package:isar/isar.dart'; class ThumbnailImage extends ConsumerWidget { /// The asset to show the thumbnail image for @@ -46,7 +46,7 @@ class ThumbnailImage extends ConsumerWidget { ? context.primaryColor.darken(amount: 0.6) : context.primaryColor.lighten(amount: 0.8); // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id - final isFromDto = asset.id == Isar.autoIncrement; + final isFromDto = asset.id == noDbId; Widget buildSelectionIcon(Asset asset) { if (isSelected) { diff --git a/mobile/lib/widgets/search/search_filter/people_picker.dart b/mobile/lib/widgets/search/search_filter/people_picker.dart index d79ae5bd95..dfc435c807 100644 --- a/mobile/lib/widgets/search/search_filter/people_picker.dart +++ b/mobile/lib/widgets/search/search_filter/people_picker.dart @@ -3,23 +3,23 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/asyncvalue_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/interfaces/person_api.interface.dart'; import 'package:immich_mobile/providers/search/people.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; -import 'package:openapi/api.dart'; class PeoplePicker extends HookConsumerWidget { const PeoplePicker({super.key, required this.onSelect, this.filter}); - final Function(Set) onSelect; - final Set? filter; + final Function(Set) onSelect; + final Set? filter; @override Widget build(BuildContext context, WidgetRef ref) { var imageSize = 45.0; final people = ref.watch(getAllPeopleProvider); final headers = ApiService.getRequestHeaders(); - final selectedPeople = useState>(filter ?? {}); + final selectedPeople = useState>(filter ?? {}); return people.widgetWhen( onData: (people) {