refactor(mobile): move user service to domain (#16782)

* refactor: user entity

* chore: rebase fixes

* refactor(mobile): move user service to domain

* fix: timeline not visible on album selection page

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong
2025-03-14 08:50:26 +05:30
committed by GitHub
parent a65ce2ac55
commit b778a86c99
23 changed files with 408 additions and 183 deletions
@@ -3,8 +3,12 @@ import 'dart:typed_data';
import 'package:immich_mobile/domain/models/user.model.dart';
abstract interface class IUserApiRepository {
Future<UserDto?> getMyUser();
Future<List<UserDto>> getAll();
Future<({String profileImagePath})> createProfileImage({
/// Saves the [data] in the server and uses it as the current users profile image
Future<String> createProfileImage({
required String name,
required Uint8List data,
});
@@ -0,0 +1,64 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:logging/logging.dart';
class UserService {
final Logger _log = Logger("UserService");
final IUserRepository _userRepository;
final IUserApiRepository _userApiRepository;
final StoreService _storeService;
UserService({
required IUserRepository userRepository,
required IUserApiRepository userApiRepository,
required StoreService storeService,
}) : _userRepository = userRepository,
_userApiRepository = userApiRepository,
_storeService = storeService;
UserDto getMyUser() {
return _storeService.get(StoreKey.currentUser);
}
UserDto? tryGetMyUser() {
return _storeService.tryGet(StoreKey.currentUser);
}
Stream<UserDto?> watchMyUser() {
return _storeService.watch(StoreKey.currentUser);
}
Future<UserDto?> refreshMyUser() async {
final user = await _userApiRepository.getMyUser();
if (user == null) return null;
await _storeService.put(StoreKey.currentUser, user);
await _userRepository.update(user);
return user;
}
Future<String?> createProfileImage(String name, Uint8List image) async {
try {
return await _userApiRepository.createProfileImage(
name: name,
data: image,
);
} catch (e) {
_log.warning("Failed to upload profile image", e);
return null;
}
}
Future<List<UserDto>> getAll() async {
return await _userRepository.getAll();
}
Future<void> deleteAll() {
return _userRepository.deleteAll();
}
}
@@ -0,0 +1,11 @@
import 'package:immich_mobile/constants/errors.dart';
class ApiRepository {
const ApiRepository();
Future<T> checkNull<T>(Future<T?> future) async {
final response = await future;
if (response == null) throw NoResponseDtoError();
return response;
}
}
@@ -1,41 +1,41 @@
import 'dart:typed_data';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:http/http.dart';
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
import 'package:immich_mobile/interfaces/user_api.interface.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/repositories/api.repository.dart';
import 'package:openapi/api.dart';
final userApiRepositoryProvider = Provider(
(ref) => UserApiRepository(
ref.watch(apiServiceProvider).usersApi,
),
);
class UserApiRepository extends ApiRepository implements IUserApiRepository {
final UsersApi _api;
const UserApiRepository(this._api);
UserApiRepository(this._api);
@override
Future<UserDto?> getMyUser() async {
final (adminDto, preferenceDto) =
await (_api.getMyUser(), _api.getMyPreferences()).wait;
if (adminDto == null) return null;
return UserConverter.fromAdminDto(adminDto, preferenceDto);
}
@override
Future<String> createProfileImage({
required String name,
required Uint8List data,
}) async {
final res = await checkNull(
_api.createProfileImage(
MultipartFile.fromBytes('file', data, filename: name),
),
);
return res.profileImagePath;
}
@override
Future<List<UserDto>> getAll() async {
final dto = await checkNull(_api.searchUsers());
return dto.map(UserConverter.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);
}
}
@@ -1,7 +1,8 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/services/user.service.dart';
final otherUsersProvider =
FutureProvider.autoDispose<List<UserDto>>((ref) async {
+4 -3
View File
@@ -1,15 +1,16 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/providers/memory.provider.dart';
import 'package:immich_mobile/services/album.service.dart';
import 'package:immich_mobile/services/asset.service.dart';
import 'package:immich_mobile/services/etag.service.dart';
import 'package:immich_mobile/services/exif.service.dart';
import 'package:immich_mobile/services/sync.service.dart';
import 'package:immich_mobile/services/user.service.dart';
import 'package:logging/logging.dart';
final assetProvider = StateNotifierProvider<AssetNotifier, bool>((ref) {
@@ -59,7 +60,7 @@ class AssetNotifier extends StateNotifier<bool> {
await clearAllAssets();
log.info("Manual refresh requested, cleared assets and albums from db");
}
final users = await _userService.getUsersFromServer();
final users = await _syncService.getUsersFromServer();
bool changedUsers = false;
if (users != null) {
changedUsers = await _syncService.syncUsersFromServer(users);
@@ -86,7 +87,7 @@ class AssetNotifier extends StateNotifier<bool> {
_assetService.clearTable(),
_exifService.clearTable(),
_albumService.clearTable(),
_userService.clearTable(),
_userService.deleteAll(),
_etagService.clearTable(),
]);
}
@@ -1,7 +1,12 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user.provider.g.dart';
@@ -9,3 +14,14 @@ part 'user.provider.g.dart';
@Riverpod(keepAlive: true)
IUserRepository userRepository(Ref ref) =>
IsarUserRepository(ref.watch(isarProvider));
@Riverpod(keepAlive: true)
IUserApiRepository userApiRepository(Ref ref) =>
UserApiRepository(ref.watch(apiServiceProvider).usersApi);
@Riverpod(keepAlive: true)
UserService userService(Ref ref) => UserService(
userRepository: ref.watch(userRepositoryProvider),
userApiRepository: ref.watch(userApiRepositoryProvider),
storeService: ref.watch(storeServiceProvider),
);
+33
View File
@@ -23,5 +23,38 @@ final userRepositoryProvider = Provider<IUserRepository>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef UserRepositoryRef = ProviderRef<IUserRepository>;
String _$userApiRepositoryHash() => r'6b19f2c99fb83162a5ceb91adb8589eaae01bc92';
/// See also [userApiRepository].
@ProviderFor(userApiRepository)
final userApiRepositoryProvider = Provider<IUserApiRepository>.internal(
userApiRepository,
name: r'userApiRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$userApiRepositoryHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef UserApiRepositoryRef = ProviderRef<IUserApiRepository>;
String _$userServiceHash() => r'4a0873357b7115b4d6bfa8e89b847c0b74ce0d93';
/// See also [userService].
@ProviderFor(userService)
final userServiceProvider = Provider<UserService>.internal(
userService,
name: r'userServiceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$userServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef UserServiceRef = ProviderRef<UserService>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
@@ -3,8 +3,8 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import 'package:immich_mobile/services/user.service.dart';
import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
enum UploadProfileStatus {
idle,
@@ -72,7 +72,7 @@ class UploadProfileImageState {
class UploadProfileImageNotifier
extends StateNotifier<UploadProfileImageState> {
UploadProfileImageNotifier(this._userSErvice)
UploadProfileImageNotifier(this._userService)
: super(
UploadProfileImageState(
profileImagePath: '',
@@ -80,18 +80,21 @@ class UploadProfileImageNotifier
),
);
final UserService _userSErvice;
final UserService _userService;
Future<bool> upload(XFile file) async {
state = state.copyWith(status: UploadProfileStatus.loading);
var res = await _userSErvice.uploadProfileImage(file);
var profileImagePath = await _userService.createProfileImage(
file.name,
await file.readAsBytes(),
);
if (res != null) {
if (profileImagePath != null) {
debugPrint("Successfully upload profile image");
state = state.copyWith(
status: UploadProfileStatus.success,
profileImagePath: res.profileImagePath,
profileImagePath: profileImagePath,
);
return true;
}
+1 -5
View File
@@ -28,12 +28,10 @@ import 'package:immich_mobile/repositories/asset.repository.dart';
import 'package:immich_mobile/repositories/backup.repository.dart';
import 'package:immich_mobile/services/entity.service.dart';
import 'package:immich_mobile/services/sync.service.dart';
import 'package:immich_mobile/services/user.service.dart';
import 'package:logging/logging.dart';
final albumServiceProvider = Provider(
(ref) => AlbumService(
ref.watch(userServiceProvider),
ref.watch(syncServiceProvider),
ref.watch(entityServiceProvider),
ref.watch(albumRepositoryProvider),
@@ -45,7 +43,6 @@ final albumServiceProvider = Provider(
);
class AlbumService {
final UserService _userService;
final SyncService _syncService;
final EntityService _entityService;
final IAlbumRepository _albumRepository;
@@ -58,7 +55,6 @@ class AlbumService {
Completer<bool> _remoteCompleter = Completer()..complete(false);
AlbumService(
this._userService,
this._syncService,
this._entityService,
this._albumRepository,
@@ -171,7 +167,7 @@ class AlbumService {
final Stopwatch sw = Stopwatch()..start();
bool changes = false;
try {
final users = await _userService.getUsersFromServer();
final users = await _syncService.getUsersFromServer();
if (users != null) {
await _syncService.syncUsersFromServer(users);
}
+2 -6
View File
@@ -20,7 +20,8 @@ import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart'
hide userServiceProvider;
import 'package:immich_mobile/repositories/asset.repository.dart';
import 'package:immich_mobile/repositories/asset_api.repository.dart';
import 'package:immich_mobile/repositories/asset_media.repository.dart';
@@ -30,7 +31,6 @@ import 'package:immich_mobile/services/album.service.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/services/backup.service.dart';
import 'package:immich_mobile/services/sync.service.dart';
import 'package:immich_mobile/services/user.service.dart';
import 'package:logging/logging.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:openapi/api.dart';
@@ -45,7 +45,6 @@ final assetServiceProvider = Provider(
ref.watch(backupAlbumRepositoryProvider),
ref.watch(apiServiceProvider),
ref.watch(syncServiceProvider),
ref.watch(userServiceProvider),
ref.watch(backupServiceProvider),
ref.watch(albumServiceProvider),
ref.watch(storeServiceProvider),
@@ -62,7 +61,6 @@ class AssetService {
final IBackupAlbumRepository _backupRepository;
final ApiService _apiService;
final SyncService _syncService;
final UserService _userService;
final BackupService _backupService;
final AlbumService _albumService;
final StoreService _storeService;
@@ -78,7 +76,6 @@ class AssetService {
this._backupRepository,
this._apiService,
this._syncService,
this._userService,
this._backupService,
this._albumService,
this._storeService,
@@ -97,7 +94,6 @@ class AssetService {
users: syncedUsers,
getChangedAssets: _getRemoteAssetChanges,
loadAssets: _getRemoteAssets,
refreshUsers: _userService.getUsersFromServer,
);
debugPrint("refreshRemoteAssets full took ${sw.elapsedMilliseconds}ms");
return changes;
+3 -7
View File
@@ -13,12 +13,14 @@ import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/entities/backup_album.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/exif.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
import 'package:immich_mobile/interfaces/backup_album.interface.dart';
import 'package:immich_mobile/interfaces/partner.interface.dart';
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
@@ -39,7 +41,6 @@ import 'package:immich_mobile/repositories/network.repository.dart';
import 'package:immich_mobile/repositories/partner.repository.dart';
import 'package:immich_mobile/repositories/partner_api.repository.dart';
import 'package:immich_mobile/repositories/permission.repository.dart';
import 'package:immich_mobile/repositories/user_api.repository.dart';
import 'package:immich_mobile/services/album.service.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
@@ -50,7 +51,6 @@ import 'package:immich_mobile/services/hash.service.dart';
import 'package:immich_mobile/services/localization.service.dart';
import 'package:immich_mobile/services/network.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';
import 'package:immich_mobile/utils/bootstrap.dart';
import 'package:immich_mobile/utils/diff.dart';
@@ -390,7 +390,7 @@ class BackgroundService {
FileMediaRepository fileMediaRepository = FileMediaRepository();
AssetMediaRepository assetMediaRepository = AssetMediaRepository();
IUserRepository userRepository = IsarUserRepository(db);
UserApiRepository userApiRepository =
IUserApiRepository userApiRepository =
UserApiRepository(apiService.usersApi);
AlbumApiRepository albumApiRepository =
AlbumApiRepository(apiService.albumsApi);
@@ -413,14 +413,10 @@ class BackgroundService {
userRepository,
StoreService.I,
eTagRepository,
);
UserService userService = UserService(
partnerApiRepository,
userApiRepository,
userRepository,
);
AlbumService albumService = AlbumService(
userService,
syncSerive,
entityService,
albumRepository,
+65 -2
View File
@@ -4,6 +4,7 @@ import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
@@ -17,6 +18,7 @@ import 'package:immich_mobile/interfaces/album_media.interface.dart';
import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/interfaces/etag.interface.dart';
import 'package:immich_mobile/interfaces/partner.interface.dart';
import 'package:immich_mobile/interfaces/partner_api.interface.dart';
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
@@ -26,6 +28,7 @@ import 'package:immich_mobile/repositories/album_media.repository.dart';
import 'package:immich_mobile/repositories/asset.repository.dart';
import 'package:immich_mobile/repositories/etag.repository.dart';
import 'package:immich_mobile/repositories/partner.repository.dart';
import 'package:immich_mobile/repositories/partner_api.repository.dart';
import 'package:immich_mobile/services/entity.service.dart';
import 'package:immich_mobile/services/hash.service.dart';
import 'package:immich_mobile/utils/async_mutex.dart';
@@ -46,6 +49,8 @@ final syncServiceProvider = Provider(
ref.watch(userRepositoryProvider),
ref.watch(storeServiceProvider),
ref.watch(etagRepositoryProvider),
ref.watch(partnerApiRepositoryProvider),
ref.watch(userApiRepositoryProvider),
),
);
@@ -61,6 +66,8 @@ class SyncService {
final IPartnerRepository _partnerRepository;
final StoreService _storeService;
final IETagRepository _eTagRepository;
final IPartnerApiRepository _partnerApiRepository;
final IUserApiRepository _userApiRepository;
final AsyncMutex _lock = AsyncMutex();
final Logger _log = Logger('SyncService');
@@ -76,6 +83,8 @@ class SyncService {
this._userRepository,
this._storeService,
this._eTagRepository,
this._partnerApiRepository,
this._userApiRepository,
);
// public methods:
@@ -95,12 +104,11 @@ class SyncService {
) getChangedAssets,
required FutureOr<List<Asset>?> Function(UserDto user, DateTime until)
loadAssets,
required FutureOr<List<UserDto>?> Function() refreshUsers,
}) =>
_lock.run(
() async =>
await _syncRemoteAssetChanges(users, getChangedAssets) ??
await _syncRemoteAssetsFull(refreshUsers, loadAssets),
await _syncRemoteAssetsFull(getUsersFromServer, loadAssets),
);
/// Syncs remote albums to the database
@@ -853,6 +861,61 @@ class SyncService {
return false;
}
}
Future<List<UserDto>?> getUsersFromServer() async {
List<UserDto>? users;
try {
users = await _userApiRepository.getAll();
} catch (e) {
_log.warning("Failed to fetch users", e);
users = null;
}
final List<UserDto> sharedBy =
await _partnerApiRepository.getAll(Direction.sharedByMe);
final List<UserDto> sharedWith =
await _partnerApiRepository.getAll(Direction.sharedWithMe);
if (users == null) {
_log.warning("Failed to refresh users");
return null;
}
users.sortBy((u) => u.uid);
sharedBy.sortBy((u) => u.uid);
sharedWith.sortBy((u) => u.uid);
final updatedSharedBy = <UserDto>[];
diffSortedListsSync(
users,
sharedBy,
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
both: (UserDto a, UserDto b) {
updatedSharedBy.add(a.copyWith(isPartnerSharedBy: true));
return true;
},
onlyFirst: (UserDto a) => updatedSharedBy.add(a),
onlySecond: (UserDto b) => updatedSharedBy.add(b),
);
final updatedSharedWith = <UserDto>[];
diffSortedListsSync(
updatedSharedBy,
sharedWith,
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
both: (UserDto a, UserDto b) {
updatedSharedWith.add(
a.copyWith(inTimeline: b.inTimeline, isPartnerSharedWith: true),
);
return true;
},
onlyFirst: (UserDto a) => updatedSharedWith.add(a),
onlySecond: (UserDto b) => updatedSharedWith.add(b),
);
return updatedSharedWith;
}
}
/// Returns a triple(toAdd, toUpdate, toRemove)
-108
View File
@@ -1,108 +0,0 @@
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/interfaces/partner_api.interface.dart';
import 'package:immich_mobile/interfaces/user_api.interface.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/repositories/partner_api.repository.dart';
import 'package:immich_mobile/repositories/user_api.repository.dart';
import 'package:immich_mobile/utils/diff.dart';
import 'package:logging/logging.dart';
final userServiceProvider = Provider(
(ref) => UserService(
ref.watch(partnerApiRepositoryProvider),
ref.watch(userApiRepositoryProvider),
ref.watch(userRepositoryProvider),
),
);
class UserService {
final IPartnerApiRepository _partnerApiRepository;
final IUserApiRepository _userApiRepository;
final IUserRepository _userRepository;
final Logger _log = Logger("UserService");
UserService(
this._partnerApiRepository,
this._userApiRepository,
this._userRepository,
);
Future<({String profileImagePath})?> uploadProfileImage(XFile image) async {
try {
return await _userApiRepository.createProfileImage(
name: image.name,
data: await image.readAsBytes(),
);
} catch (e) {
_log.warning("Failed to upload profile image", e);
return null;
}
}
Future<List<UserDto>> getAll() async {
return await _userRepository.getAll();
}
Future<List<UserDto>?> getUsersFromServer() async {
List<UserDto>? users;
try {
users = await _userApiRepository.getAll();
} catch (e) {
_log.warning("Failed to fetch users", e);
users = null;
}
final List<UserDto> sharedBy =
await _partnerApiRepository.getAll(Direction.sharedByMe);
final List<UserDto> sharedWith =
await _partnerApiRepository.getAll(Direction.sharedWithMe);
if (users == null) {
_log.warning("Failed to refresh users");
return null;
}
users.sortBy((u) => u.uid);
sharedBy.sortBy((u) => u.uid);
sharedWith.sortBy((u) => u.uid);
final updatedSharedBy = <UserDto>[];
diffSortedListsSync(
users,
sharedBy,
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
both: (UserDto a, UserDto b) {
updatedSharedBy.add(a.copyWith(isPartnerSharedBy: true));
return true;
},
onlyFirst: (UserDto a) => updatedSharedBy.add(a),
onlySecond: (UserDto b) => updatedSharedBy.add(b),
);
final updatedSharedWith = <UserDto>[];
diffSortedListsSync(
updatedSharedBy,
sharedWith,
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
both: (UserDto a, UserDto b) {
updatedSharedWith.add(
a.copyWith(inTimeline: b.inTimeline, isPartnerSharedWith: true),
);
return true;
},
onlyFirst: (UserDto a) => updatedSharedWith.add(a),
onlySecond: (UserDto b) => updatedSharedWith.add(b),
);
return updatedSharedWith;
}
Future<void> clearTable() {
return _userRepository.deleteAll();
}
}
+3 -3
View File
@@ -1,11 +1,11 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/repositories/activity_api.repository.dart';
import 'package:immich_mobile/repositories/album_api.repository.dart';
import 'package:immich_mobile/repositories/asset_api.repository.dart';
import 'package:immich_mobile/repositories/partner_api.repository.dart';
import 'package:immich_mobile/repositories/person_api.repository.dart';
import 'package:immich_mobile/repositories/user_api.repository.dart';
import 'package:immich_mobile/repositories/timeline.repository.dart';
void invalidateAllApiRepositoryProviders(WidgetRef ref) {
ref.invalidate(userApiRepositoryProvider);
@@ -14,5 +14,5 @@ void invalidateAllApiRepositoryProviders(WidgetRef ref) {
ref.invalidate(albumApiRepositoryProvider);
ref.invalidate(personApiRepositoryProvider);
ref.invalidate(assetApiRepositoryProvider);
ref.invalidate(timelineUsersIdsProvider);
ref.invalidate(timelineRepositoryProvider);
}