refactor(mobile): (1) user.interface.dart (#19322)

* refactor(mobile): user.interface.dart

* generate files

* refactor(mobile): (2) user_api.interface.dart (#19323)

* refactor(mobile): (2) user_api.interface.dart

* generate files

* refactor(mobile): (3) sync_stream.interface.dart (#19325)
This commit is contained in:
Alex 2025-06-19 18:25:18 -05:00 committed by GitHub
parent a4c0dc5007
commit bce4f93c90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 82 additions and 157 deletions

View File

@ -10,3 +10,5 @@ enum TextSearchType {
} }
enum AssetVisibilityEnum { timeline, hidden, archive, locked } enum AssetVisibilityEnum { timeline, hidden, archive, locked }
enum SortUserBy { id }

View File

@ -1,18 +0,0 @@
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
import 'package:openapi/api.dart';
abstract interface class ISyncStreamRepository implements IDatabaseRepository {
Future<void> updateUsersV1(Iterable<SyncUserV1> data);
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data);
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data);
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data);
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data);
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data);
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data);
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data);
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data);
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data);
}

View File

@ -1,22 +0,0 @@
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
abstract interface class IUserRepository implements IDatabaseRepository {
Future<bool> insert(UserDto user);
Future<UserDto?> getByUserId(String id);
Future<List<UserDto?>> getByUserIds(List<String> ids);
Future<List<UserDto>> getAll({SortUserBy? sortBy});
Future<bool> updateAll(List<UserDto> users);
Future<UserDto> update(UserDto user);
Future<void> delete(List<String> ids);
Future<void> deleteAll();
}
enum SortUserBy { id }

View File

@ -1,15 +0,0 @@
import 'dart:typed_data';
import 'package:immich_mobile/domain/models/user.model.dart';
abstract interface class IUserApiRepository {
Future<UserDto?> getMyUser();
Future<List<UserDto>> getAll();
/// Saves the [data] in the server and uses it as the current users profile image
Future<String> createProfileImage({
required String name,
required Uint8List data,
});
}

View File

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart'; import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
import 'package:immich_mobile/domain/models/sync_event.model.dart'; import 'package:immich_mobile/domain/models/sync_event.model.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
@ -10,12 +10,12 @@ class SyncStreamService {
final Logger _logger = Logger('SyncStreamService'); final Logger _logger = Logger('SyncStreamService');
final ISyncApiRepository _syncApiRepository; final ISyncApiRepository _syncApiRepository;
final ISyncStreamRepository _syncStreamRepository; final SyncStreamRepository _syncStreamRepository;
final bool Function()? _cancelChecker; final bool Function()? _cancelChecker;
SyncStreamService({ SyncStreamService({
required ISyncApiRepository syncApiRepository, required ISyncApiRepository syncApiRepository,
required ISyncStreamRepository syncStreamRepository, required SyncStreamRepository syncStreamRepository,
bool Function()? cancelChecker, bool Function()? cancelChecker,
}) : _syncApiRepository = syncApiRepository, }) : _syncApiRepository = syncApiRepository,
_syncStreamRepository = syncStreamRepository, _syncStreamRepository = syncStreamRepository,

View File

@ -1,24 +1,24 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
class UserService { class UserService {
final Logger _log = Logger("UserService"); final Logger _log = Logger("UserService");
final IUserRepository _userRepository; final IsarUserRepository _isarUserRepository;
final IUserApiRepository _userApiRepository; final UserApiRepository _userApiRepository;
final StoreService _storeService; final StoreService _storeService;
UserService({ UserService({
required IUserRepository userRepository, required IsarUserRepository isarUserRepository,
required IUserApiRepository userApiRepository, required UserApiRepository userApiRepository,
required StoreService storeService, required StoreService storeService,
}) : _userRepository = userRepository, }) : _isarUserRepository = isarUserRepository,
_userApiRepository = userApiRepository, _userApiRepository = userApiRepository,
_storeService = storeService; _storeService = storeService;
@ -38,7 +38,7 @@ class UserService {
final user = await _userApiRepository.getMyUser(); final user = await _userApiRepository.getMyUser();
if (user == null) return null; if (user == null) return null;
await _storeService.put(StoreKey.currentUser, user); await _storeService.put(StoreKey.currentUser, user);
await _userRepository.update(user); await _isarUserRepository.update(user);
return user; return user;
} }
@ -50,7 +50,7 @@ class UserService {
); );
final updatedUser = getMyUser().copyWith(profileImagePath: path); final updatedUser = getMyUser().copyWith(profileImagePath: path);
await _storeService.put(StoreKey.currentUser, updatedUser); await _storeService.put(StoreKey.currentUser, updatedUser);
await _userRepository.update(updatedUser); await _isarUserRepository.update(updatedUser);
return path; return path;
} catch (e) { } catch (e) {
_log.warning("Failed to upload profile image", e); _log.warning("Failed to upload profile image", e);
@ -59,10 +59,10 @@ class UserService {
} }
Future<List<UserDto>> getAll() async { Future<List<UserDto>> getAll() async {
return await _userRepository.getAll(); return await _isarUserRepository.getAll();
} }
Future<void> deleteAll() { Future<void> deleteAll() {
return _userRepository.deleteAll(); return _isarUserRepository.deleteAll();
} }
} }

View File

@ -1,5 +1,4 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
@ -10,14 +9,12 @@ import 'package:logging/logging.dart';
import 'package:openapi/api.dart' as api show AssetVisibility; import 'package:openapi/api.dart' as api show AssetVisibility;
import 'package:openapi/api.dart' hide AssetVisibility; import 'package:openapi/api.dart' hide AssetVisibility;
class DriftSyncStreamRepository extends DriftDatabaseRepository class SyncStreamRepository extends DriftDatabaseRepository {
implements ISyncStreamRepository {
final Logger _logger = Logger('DriftSyncStreamRepository'); final Logger _logger = Logger('DriftSyncStreamRepository');
final Drift _db; final Drift _db;
DriftSyncStreamRepository(super.db) : _db = db; SyncStreamRepository(super.db) : _db = db;
@override
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async { Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
try { try {
await _db.batch((batch) { await _db.batch((batch) {
@ -34,7 +31,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async { Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
try { try {
await _db.batch((batch) { await _db.batch((batch) {
@ -57,7 +53,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async { Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
try { try {
await _db.batch((batch) { await _db.batch((batch) {
@ -77,7 +72,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async { Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
try { try {
await _db.batch((batch) { await _db.batch((batch) {
@ -101,7 +95,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async { Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
try { try {
await _deleteAssetsV1(data); await _deleteAssetsV1(data);
@ -111,7 +104,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async { Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
try { try {
await _updateAssetsV1(data); await _updateAssetsV1(data);
@ -121,7 +113,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async { Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
try { try {
await _deleteAssetsV1(data); await _deleteAssetsV1(data);
@ -131,7 +122,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async { Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
try { try {
await _updateAssetsV1(data); await _updateAssetsV1(data);
@ -141,7 +131,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async { Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
try { try {
await _updateAssetExifV1(data); await _updateAssetExifV1(data);
@ -151,7 +140,6 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
} }
} }
@override
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async { Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
try { try {
await _updateAssetExifV1(data); await _updateAssetExifV1(data);

View File

@ -1,30 +1,26 @@
import 'package:immich_mobile/domain/interfaces/user.interface.dart'; import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart' import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
as entity; as entity;
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
class IsarUserRepository extends IsarDatabaseRepository class IsarUserRepository extends IsarDatabaseRepository {
implements IUserRepository {
final Isar _db; final Isar _db;
const IsarUserRepository(super.db) : _db = db; const IsarUserRepository(super.db) : _db = db;
@override
Future<void> delete(List<String> ids) async { Future<void> delete(List<String> ids) async {
await transaction(() async { await transaction(() async {
await _db.users.deleteAllById(ids); await _db.users.deleteAllById(ids);
}); });
} }
@override
Future<void> deleteAll() async { Future<void> deleteAll() async {
await transaction(() async { await transaction(() async {
await _db.users.clear(); await _db.users.clear();
}); });
} }
@override
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async { Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
return (await _db.users return (await _db.users
.where() .where()
@ -39,17 +35,14 @@ class IsarUserRepository extends IsarDatabaseRepository
.toList(); .toList();
} }
@override
Future<UserDto?> getByUserId(String id) async { Future<UserDto?> getByUserId(String id) async {
return (await _db.users.getById(id))?.toDto(); return (await _db.users.getById(id))?.toDto();
} }
@override
Future<List<UserDto?>> getByUserIds(List<String> ids) async { Future<List<UserDto?>> getByUserIds(List<String> ids) async {
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList(); return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
} }
@override
Future<bool> insert(UserDto user) async { Future<bool> insert(UserDto user) async {
await transaction(() async { await transaction(() async {
await _db.users.put(entity.User.fromDto(user)); await _db.users.put(entity.User.fromDto(user));
@ -57,7 +50,6 @@ class IsarUserRepository extends IsarDatabaseRepository
return true; return true;
} }
@override
Future<UserDto> update(UserDto user) async { Future<UserDto> update(UserDto user) async {
await transaction(() async { await transaction(() async {
await _db.users.put(entity.User.fromDto(user)); await _db.users.put(entity.User.fromDto(user));
@ -65,7 +57,6 @@ class IsarUserRepository extends IsarDatabaseRepository
return user; return user;
} }
@override
Future<bool> updateAll(List<UserDto> users) async { Future<bool> updateAll(List<UserDto> users) async {
await transaction(() async { await transaction(() async {
await _db.users.putAll(users.map(entity.User.fromDto).toList()); await _db.users.putAll(users.map(entity.User.fromDto).toList());

View File

@ -1,17 +1,15 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
import 'package:immich_mobile/infrastructure/utils/user.converter.dart'; import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
class UserApiRepository extends ApiRepository implements IUserApiRepository { class UserApiRepository extends ApiRepository {
final UsersApi _api; final UsersApi _api;
const UserApiRepository(this._api); const UserApiRepository(this._api);
@override
Future<UserDto?> getMyUser() async { Future<UserDto?> getMyUser() async {
final (adminDto, preferenceDto) = final (adminDto, preferenceDto) =
await (_api.getMyUser(), _api.getMyPreferences()).wait; await (_api.getMyUser(), _api.getMyPreferences()).wait;
@ -20,7 +18,6 @@ class UserApiRepository extends ApiRepository implements IUserApiRepository {
return UserConverter.fromAdminDto(adminDto, preferenceDto); return UserConverter.fromAdminDto(adminDto, preferenceDto);
} }
@override
Future<String> createProfileImage({ Future<String> createProfileImage({
required String name, required String name,
required Uint8List data, required Uint8List data,
@ -33,7 +30,6 @@ class UserApiRepository extends ApiRepository implements IUserApiRepository {
return res.profileImagePath; return res.profileImagePath;
} }
@override
Future<List<UserDto>> getAll() async { Future<List<UserDto>> getAll() async {
final dto = await checkNull(_api.searchUsers()); final dto = await checkNull(_api.searchUsers());
return dto.map(UserConverter.fromSimpleUserDto).toList(); return dto.map(UserConverter.fromSimpleUserDto).toList();

View File

@ -26,7 +26,7 @@ final syncApiRepositoryProvider = Provider(
); );
final syncStreamRepositoryProvider = Provider( final syncStreamRepositoryProvider = Provider(
(ref) => DriftSyncStreamRepository(ref.watch(driftProvider)), (ref) => SyncStreamRepository(ref.watch(driftProvider)),
); );
final localSyncServiceProvider = Provider( final localSyncServiceProvider = Provider(

View File

@ -1,6 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
import 'package:immich_mobile/domain/services/user.service.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.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
@ -12,16 +10,16 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user.provider.g.dart'; part 'user.provider.g.dart';
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
IUserRepository userRepository(Ref ref) => IsarUserRepository userRepository(Ref ref) =>
IsarUserRepository(ref.watch(isarProvider)); IsarUserRepository(ref.watch(isarProvider));
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
IUserApiRepository userApiRepository(Ref ref) => UserApiRepository userApiRepository(Ref ref) =>
UserApiRepository(ref.watch(apiServiceProvider).usersApi); UserApiRepository(ref.watch(apiServiceProvider).usersApi);
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
UserService userService(Ref ref) => UserService( UserService userService(Ref ref) => UserService(
userRepository: ref.watch(userRepositoryProvider), isarUserRepository: ref.watch(userRepositoryProvider),
userApiRepository: ref.watch(userApiRepositoryProvider), userApiRepository: ref.watch(userApiRepositoryProvider),
storeService: ref.watch(storeServiceProvider), storeService: ref.watch(storeServiceProvider),
); );

View File

@ -6,11 +6,11 @@ part of 'user.provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$userRepositoryHash() => r'1a2ac726bcc44397dcaecf449084fefd336696d4'; String _$userRepositoryHash() => r'538791a4ad126ed086c9db682c67fc5c654d54f3';
/// See also [userRepository]. /// See also [userRepository].
@ProviderFor(userRepository) @ProviderFor(userRepository)
final userRepositoryProvider = Provider<IUserRepository>.internal( final userRepositoryProvider = Provider<IsarUserRepository>.internal(
userRepository, userRepository,
name: r'userRepositoryProvider', name: r'userRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@ -22,12 +22,12 @@ final userRepositoryProvider = Provider<IUserRepository>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
typedef UserRepositoryRef = ProviderRef<IUserRepository>; typedef UserRepositoryRef = ProviderRef<IsarUserRepository>;
String _$userApiRepositoryHash() => r'6b19f2c99fb83162a5ceb91adb8589eaae01bc92'; String _$userApiRepositoryHash() => r'8a7340ca4544c8c6b20225c65bff2abb9e96baa2';
/// See also [userApiRepository]. /// See also [userApiRepository].
@ProviderFor(userApiRepository) @ProviderFor(userApiRepository)
final userApiRepositoryProvider = Provider<IUserApiRepository>.internal( final userApiRepositoryProvider = Provider<UserApiRepository>.internal(
userApiRepository, userApiRepository,
name: r'userApiRepositoryProvider', name: r'userApiRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@ -39,8 +39,8 @@ final userApiRepositoryProvider = Provider<IUserApiRepository>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
typedef UserApiRepositoryRef = ProviderRef<IUserApiRepository>; typedef UserApiRepositoryRef = ProviderRef<UserApiRepository>;
String _$userServiceHash() => r'4a0873357b7115b4d6bfa8e89b847c0b74ce0d93'; String _$userServiceHash() => r'181414dddc7891be6237e13d568c287a804228d1';
/// See also [userService]. /// See also [userService].
@ProviderFor(userService) @ProviderFor(userService)

View File

@ -5,11 +5,11 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/interfaces/exif.interface.dart'; import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/backup_album.entity.dart'; import 'package:immich_mobile/entities/backup_album.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/interfaces/asset_api.interface.dart'; import 'package:immich_mobile/interfaces/asset_api.interface.dart';
import 'package:immich_mobile/interfaces/asset_media.interface.dart'; import 'package:immich_mobile/interfaces/asset_media.interface.dart';
@ -53,7 +53,7 @@ class AssetService {
final IAssetApiRepository _assetApiRepository; final IAssetApiRepository _assetApiRepository;
final IAssetRepository _assetRepository; final IAssetRepository _assetRepository;
final IExifInfoRepository _exifInfoRepository; final IExifInfoRepository _exifInfoRepository;
final IUserRepository _userRepository; final IsarUserRepository _isarUserRepository;
final IETagRepository _etagRepository; final IETagRepository _etagRepository;
final IBackupAlbumRepository _backupRepository; final IBackupAlbumRepository _backupRepository;
final ApiService _apiService; final ApiService _apiService;
@ -68,7 +68,7 @@ class AssetService {
this._assetApiRepository, this._assetApiRepository,
this._assetRepository, this._assetRepository,
this._exifInfoRepository, this._exifInfoRepository,
this._userRepository, this._isarUserRepository,
this._etagRepository, this._etagRepository,
this._backupRepository, this._backupRepository,
this._apiService, this._apiService,
@ -85,7 +85,9 @@ class AssetService {
final syncedUserIds = await _etagRepository.getAllIds(); final syncedUserIds = await _etagRepository.getAllIds();
final List<UserDto> syncedUsers = syncedUserIds.isEmpty final List<UserDto> syncedUsers = syncedUserIds.isEmpty
? [] ? []
: (await _userRepository.getByUserIds(syncedUserIds)).nonNulls.toList(); : (await _isarUserRepository.getByUserIds(syncedUserIds))
.nonNulls
.toList();
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
final bool changes = await _syncService.syncRemoteAssetsToDb( final bool changes = await _syncService.syncRemoteAssetsToDb(
users: syncedUsers, users: syncedUsers,

View File

@ -1,24 +1,24 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'; import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/interfaces/asset.interface.dart'; import 'package:immich_mobile/interfaces/asset.interface.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
import 'package:immich_mobile/repositories/asset.repository.dart'; import 'package:immich_mobile/repositories/asset.repository.dart';
class EntityService { class EntityService {
final IAssetRepository _assetRepository; final IAssetRepository _assetRepository;
final IUserRepository _userRepository; final IsarUserRepository _isarUserRepository;
EntityService( EntityService(
this._assetRepository, this._assetRepository,
this._userRepository, this._isarUserRepository,
); );
Future<Album> fillAlbumWithDatabaseEntities(Album album) async { Future<Album> fillAlbumWithDatabaseEntities(Album album) async {
final ownerId = album.ownerId; final ownerId = album.ownerId;
if (ownerId != null) { if (ownerId != null) {
// replace owner with user from database // replace owner with user from database
final user = await _userRepository.getByUserId(ownerId); final user = await _isarUserRepository.getByUserId(ownerId);
album.owner.value = user == null ? null : User.fromDto(user); album.owner.value = user == null ? null : User.fromDto(user);
} }
final thumbnailAssetId = final thumbnailAssetId =
@ -30,7 +30,7 @@ class EntityService {
} }
if (album.remoteUsers.isNotEmpty) { if (album.remoteUsers.isNotEmpty) {
// replace all users with users from database // replace all users with users from database
final users = await _userRepository final users = await _isarUserRepository
.getByUserIds(album.remoteUsers.map((user) => user.id).toList()); .getByUserIds(album.remoteUsers.map((user) => user.id).toList());
album.sharedUsers.clear(); album.sharedUsers.clear();
album.sharedUsers.addAll(users.nonNulls.map(User.fromDto)); album.sharedUsers.addAll(users.nonNulls.map(User.fromDto));

View File

@ -1,6 +1,6 @@
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/interfaces/partner.interface.dart'; import 'package:immich_mobile/interfaces/partner.interface.dart';
import 'package:immich_mobile/interfaces/partner_api.interface.dart'; import 'package:immich_mobile/interfaces/partner_api.interface.dart';
import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
@ -19,12 +19,12 @@ final partnerServiceProvider = Provider(
class PartnerService { class PartnerService {
final IPartnerApiRepository _partnerApiRepository; final IPartnerApiRepository _partnerApiRepository;
final IPartnerRepository _partnerRepository; final IPartnerRepository _partnerRepository;
final IUserRepository _userRepository; final IsarUserRepository _isarUserRepository;
final Logger _log = Logger("PartnerService"); final Logger _log = Logger("PartnerService");
PartnerService( PartnerService(
this._partnerApiRepository, this._partnerApiRepository,
this._userRepository, this._isarUserRepository,
this._partnerRepository, this._partnerRepository,
); );
@ -47,7 +47,8 @@ class PartnerService {
Future<bool> removePartner(UserDto partner) async { Future<bool> removePartner(UserDto partner) async {
try { try {
await _partnerApiRepository.delete(partner.id); await _partnerApiRepository.delete(partner.id);
await _userRepository.update(partner.copyWith(isPartnerSharedBy: false)); await _isarUserRepository
.update(partner.copyWith(isPartnerSharedBy: false));
} catch (e) { } catch (e) {
_log.warning("Failed to remove partner ${partner.id}", e); _log.warning("Failed to remove partner ${partner.id}", e);
return false; return false;
@ -58,7 +59,8 @@ class PartnerService {
Future<bool> addPartner(UserDto partner) async { Future<bool> addPartner(UserDto partner) async {
try { try {
await _partnerApiRepository.create(partner.id); await _partnerApiRepository.create(partner.id);
await _userRepository.update(partner.copyWith(isPartnerSharedBy: true)); await _isarUserRepository
.update(partner.copyWith(isPartnerSharedBy: true));
return true; return true;
} catch (e) { } catch (e) {
_log.warning("Failed to add partner ${partner.id}", e); _log.warning("Failed to add partner ${partner.id}", e);
@ -75,7 +77,7 @@ class PartnerService {
partner.id, partner.id,
inTimeline: inTimeline, inTimeline: inTimeline,
); );
await _userRepository await _isarUserRepository
.update(partner.copyWith(inTimeline: dto.inTimeline)); .update(partner.copyWith(inTimeline: dto.inTimeline));
return true; return true;
} catch (e) { } catch (e) {

View File

@ -3,15 +3,16 @@ import 'dart:io';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/interfaces/exif.interface.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.interface.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/user.service.dart'; import 'package:immich_mobile/domain/services/user.service.dart';
import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/etag.entity.dart';
import 'package:immich_mobile/extensions/collection_extensions.dart'; import 'package:immich_mobile/extensions/collection_extensions.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/album.interface.dart'; import 'package:immich_mobile/interfaces/album.interface.dart';
import 'package:immich_mobile/interfaces/album_api.interface.dart'; import 'package:immich_mobile/interfaces/album_api.interface.dart';
import 'package:immich_mobile/interfaces/album_media.interface.dart'; import 'package:immich_mobile/interfaces/album_media.interface.dart';
@ -68,12 +69,12 @@ class SyncService {
final IAlbumRepository _albumRepository; final IAlbumRepository _albumRepository;
final IAssetRepository _assetRepository; final IAssetRepository _assetRepository;
final IExifInfoRepository _exifInfoRepository; final IExifInfoRepository _exifInfoRepository;
final IUserRepository _userRepository; final IsarUserRepository _isarUserRepository;
final UserService _userService; final UserService _userService;
final IPartnerRepository _partnerRepository; final IPartnerRepository _partnerRepository;
final IETagRepository _eTagRepository; final IETagRepository _eTagRepository;
final IPartnerApiRepository _partnerApiRepository; final IPartnerApiRepository _partnerApiRepository;
final IUserApiRepository _userApiRepository; final UserApiRepository _userApiRepository;
final AsyncMutex _lock = AsyncMutex(); final AsyncMutex _lock = AsyncMutex();
final Logger _log = Logger('SyncService'); final Logger _log = Logger('SyncService');
final AppSettingsService _appSettingsService; final AppSettingsService _appSettingsService;
@ -88,7 +89,7 @@ class SyncService {
this._assetRepository, this._assetRepository,
this._exifInfoRepository, this._exifInfoRepository,
this._partnerRepository, this._partnerRepository,
this._userRepository, this._isarUserRepository,
this._userService, this._userService,
this._eTagRepository, this._eTagRepository,
this._appSettingsService, this._appSettingsService,
@ -165,7 +166,7 @@ class SyncService {
/// Returns `true`if there were any changes /// Returns `true`if there were any changes
Future<bool> _syncUsersFromServer(List<UserDto> users) async { Future<bool> _syncUsersFromServer(List<UserDto> users) async {
users.sortBy((u) => u.id); users.sortBy((u) => u.id);
final dbUsers = await _userRepository.getAll(sortBy: SortUserBy.id); final dbUsers = await _isarUserRepository.getAll(sortBy: SortUserBy.id);
final List<String> toDelete = []; final List<String> toDelete = [];
final List<UserDto> toUpsert = []; final List<UserDto> toUpsert = [];
final changes = diffSortedListsSync( final changes = diffSortedListsSync(
@ -186,9 +187,9 @@ class SyncService {
onlySecond: (UserDto b) => toDelete.add(b.id), onlySecond: (UserDto b) => toDelete.add(b.id),
); );
if (changes) { if (changes) {
await _userRepository.transaction(() async { await _isarUserRepository.transaction(() async {
await _userRepository.delete(toDelete); await _isarUserRepository.delete(toDelete);
await _userRepository.updateAll(toUpsert); await _isarUserRepository.updateAll(toUpsert);
}); });
} }
return changes; return changes;
@ -448,7 +449,7 @@ class SyncService {
final (existingInDb, updated) = await _linkWithExistingFromDb(toAdd); final (existingInDb, updated) = await _linkWithExistingFromDb(toAdd);
await upsertAssetsWithExif(updated); await upsertAssetsWithExif(updated);
final assetsToLink = existingInDb + updated; final assetsToLink = existingInDb + updated;
final usersToLink = await _userRepository.getByUserIds(userIdsToAdd); final usersToLink = await _isarUserRepository.getByUserIds(userIdsToAdd);
album.name = dto.name; album.name = dto.name;
album.description = dto.description; album.description = dto.description;

View File

@ -4,9 +4,9 @@ import 'dart:async';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart'; import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
import 'package:immich_mobile/domain/models/sync_event.model.dart'; import 'package:immich_mobile/domain/models/sync_event.model.dart';
import 'package:immich_mobile/domain/services/sync_stream.service.dart'; import 'package:immich_mobile/domain/services/sync_stream.service.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import '../../fixtures/sync_stream.stub.dart'; import '../../fixtures/sync_stream.stub.dart';
@ -30,7 +30,7 @@ class _MockCancellationWrapper extends Mock implements _CancellationWrapper {}
void main() { void main() {
late SyncStreamService sut; late SyncStreamService sut;
late ISyncStreamRepository mockSyncStreamRepo; late SyncStreamRepository mockSyncStreamRepo;
late ISyncApiRepository mockSyncApiRepo; late ISyncApiRepository mockSyncApiRepo;
late Function(List<SyncEvent>, Function()) handleEventsCallback; late Function(List<SyncEvent>, Function()) handleEventsCallback;
late _MockAbortCallbackWrapper mockAbortCallbackWrapper; late _MockAbortCallbackWrapper mockAbortCallbackWrapper;

View File

@ -1,11 +1,11 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/services/store.service.dart'; import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/domain/services/user.service.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:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import '../../fixtures/user.stub.dart'; import '../../fixtures/user.stub.dart';
@ -14,16 +14,16 @@ import '../service.mock.dart';
void main() { void main() {
late UserService sut; late UserService sut;
late IUserRepository mockUserRepo; late IsarUserRepository mockUserRepo;
late IUserApiRepository mockUserApiRepo; late UserApiRepository mockUserApiRepo;
late StoreService mockStoreService; late StoreService mockStoreService;
setUp(() { setUp(() {
mockUserRepo = MockUserRepository(); mockUserRepo = MockIsarUserRepository();
mockUserApiRepo = MockUserApiRepository(); mockUserApiRepo = MockUserApiRepository();
mockStoreService = MockStoreService(); mockStoreService = MockStoreService();
sut = UserService( sut = UserService(
userRepository: mockUserRepo, isarUserRepository: mockUserRepo,
userApiRepository: mockUserApiRepo, userApiRepository: mockUserApiRepo,
storeService: mockStoreService, storeService: mockStoreService,
); );

View File

@ -5,21 +5,21 @@ import 'package:immich_mobile/domain/interfaces/log.interface.dart';
import 'package:immich_mobile/domain/interfaces/storage.interface.dart'; import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
import 'package:immich_mobile/domain/interfaces/store.interface.dart'; import 'package:immich_mobile/domain/interfaces/store.interface.dart';
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart'; import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart'; import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart'; import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart'; import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
class MockStoreRepository extends Mock implements IStoreRepository {} class MockStoreRepository extends Mock implements IStoreRepository {}
class MockLogRepository extends Mock implements ILogRepository {} class MockLogRepository extends Mock implements ILogRepository {}
class MockUserRepository extends Mock implements IUserRepository {} class MockIsarUserRepository extends Mock implements IsarUserRepository {}
class MockDeviceAssetRepository extends Mock class MockDeviceAssetRepository extends Mock
implements IDeviceAssetRepository {} implements IDeviceAssetRepository {}
class MockSyncStreamRepository extends Mock implements ISyncStreamRepository {} class MockSyncStreamRepository extends Mock implements SyncStreamRepository {}
class MockLocalAlbumRepository extends Mock implements ILocalAlbumRepository {} class MockLocalAlbumRepository extends Mock implements ILocalAlbumRepository {}
@ -28,6 +28,6 @@ class MockLocalAssetRepository extends Mock implements ILocalAssetRepository {}
class MockStorageRepository extends Mock implements IStorageRepository {} class MockStorageRepository extends Mock implements IStorageRepository {}
// API Repos // API Repos
class MockUserApiRepository extends Mock implements IUserApiRepository {} class MockUserApiRepository extends Mock implements UserApiRepository {}
class MockSyncApiRepository extends Mock implements ISyncApiRepository {} class MockSyncApiRepository extends Mock implements ISyncApiRepository {}

View File

@ -1,6 +1,6 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart'; import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/domain/services/log.service.dart'; import 'package:immich_mobile/domain/services/log.service.dart';
@ -55,7 +55,7 @@ void main() {
final MockAlbumRepository albumRepository = MockAlbumRepository(); final MockAlbumRepository albumRepository = MockAlbumRepository();
final MockAssetRepository assetRepository = MockAssetRepository(); final MockAssetRepository assetRepository = MockAssetRepository();
final MockExifInfoRepository exifInfoRepository = MockExifInfoRepository(); final MockExifInfoRepository exifInfoRepository = MockExifInfoRepository();
final MockUserRepository userRepository = MockUserRepository(); final MockIsarUserRepository userRepository = MockIsarUserRepository();
final MockETagRepository eTagRepository = MockETagRepository(); final MockETagRepository eTagRepository = MockETagRepository();
final MockAlbumMediaRepository albumMediaRepository = final MockAlbumMediaRepository albumMediaRepository =
MockAlbumMediaRepository(); MockAlbumMediaRepository();

View File

@ -22,7 +22,7 @@ void main() {
late MockExifInfoRepository exifInfoRepository; late MockExifInfoRepository exifInfoRepository;
late MockETagRepository eTagRepository; late MockETagRepository eTagRepository;
late MockBackupAlbumRepository backupAlbumRepository; late MockBackupAlbumRepository backupAlbumRepository;
late MockUserRepository userRepository; late MockIsarUserRepository userRepository;
late MockAssetMediaRepository assetMediaRepository; late MockAssetMediaRepository assetMediaRepository;
late MockApiService apiService; late MockApiService apiService;
@ -35,7 +35,7 @@ void main() {
assetRepository = MockAssetRepository(); assetRepository = MockAssetRepository();
assetApiRepository = MockAssetApiRepository(); assetApiRepository = MockAssetApiRepository();
exifInfoRepository = MockExifInfoRepository(); exifInfoRepository = MockExifInfoRepository();
userRepository = MockUserRepository(); userRepository = MockIsarUserRepository();
eTagRepository = MockETagRepository(); eTagRepository = MockETagRepository();
backupAlbumRepository = MockBackupAlbumRepository(); backupAlbumRepository = MockBackupAlbumRepository();
apiService = MockApiService(); apiService = MockApiService();

View File

@ -12,11 +12,11 @@ import '../repository.mocks.dart';
void main() { void main() {
late EntityService sut; late EntityService sut;
late MockAssetRepository assetRepository; late MockAssetRepository assetRepository;
late MockUserRepository userRepository; late MockIsarUserRepository userRepository;
setUp(() { setUp(() {
assetRepository = MockAssetRepository(); assetRepository = MockAssetRepository();
userRepository = MockUserRepository(); userRepository = MockIsarUserRepository();
sut = EntityService(assetRepository, userRepository); sut = EntityService(assetRepository, userRepository);
}); });