mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
refactor: user entity (#16655)
* refactor: user entity * fix: add users to album & user profile url * chore: rebase fixes * generate files * fix(mobile): timeline not reset on login * fix: test stub * refactor: rename user model (#16813) * refactor: rename user model * simplify import --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com> * chore: generate files * fix: use getAllAccessible instead of getAll --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
parent
a75718ce99
commit
d1c8fe5303
82 changed files with 1039 additions and 947 deletions
|
|
@ -7,11 +7,13 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
|
||||
as entity;
|
||||
import 'package:immich_mobile/interfaces/album.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/album_api.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/album_media.interface.dart';
|
||||
|
|
@ -202,12 +204,12 @@ class AlbumService {
|
|||
Future<Album?> createAlbum(
|
||||
String albumName,
|
||||
Iterable<Asset> assets, [
|
||||
Iterable<User> sharedUsers = const [],
|
||||
Iterable<UserDto> sharedUsers = const [],
|
||||
]) async {
|
||||
final Album album = await _albumApiRepository.create(
|
||||
albumName,
|
||||
assetIds: assets.map((asset) => asset.remoteId!),
|
||||
sharedUserIds: sharedUsers.map((user) => user.id),
|
||||
sharedUserIds: sharedUsers.map((user) => user.uid),
|
||||
);
|
||||
await _entityService.fillAlbumWithDatabaseEntities(album);
|
||||
return _albumRepository.create(album);
|
||||
|
|
@ -294,7 +296,7 @@ class AlbumService {
|
|||
|
||||
Future<bool> deleteAlbum(Album album) async {
|
||||
try {
|
||||
final userId = Store.get(StoreKey.currentUser).isarId;
|
||||
final userId = Store.get(StoreKey.currentUser).id;
|
||||
if (album.owner.value?.isarId == userId) {
|
||||
await _albumApiRepository.delete(album.remoteId!);
|
||||
}
|
||||
|
|
@ -356,15 +358,15 @@ class AlbumService {
|
|||
|
||||
Future<bool> removeUser(
|
||||
Album album,
|
||||
User user,
|
||||
UserDto user,
|
||||
) async {
|
||||
try {
|
||||
await _albumApiRepository.removeUser(
|
||||
album.remoteId!,
|
||||
userId: user.id,
|
||||
userId: user.uid,
|
||||
);
|
||||
|
||||
album.sharedUsers.remove(user);
|
||||
album.sharedUsers.remove(entity.User.fromDto(user));
|
||||
await _albumRepository.removeUsers(album, [user]);
|
||||
final a = await _albumRepository.get(album.id);
|
||||
// trigger watcher
|
||||
|
|
@ -388,7 +390,10 @@ class AlbumService {
|
|||
album.sharedUsers.addAll(updatedAlbum.remoteUsers);
|
||||
album.shared = true;
|
||||
|
||||
await _albumRepository.addUsers(album, album.sharedUsers.toList());
|
||||
await _albumRepository.addUsers(
|
||||
album,
|
||||
album.sharedUsers.map((u) => u.toDto()).toList(),
|
||||
);
|
||||
await _albumRepository.update(album);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -5,24 +5,27 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter/material.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/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.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/backup_album.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/etag.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
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/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/repositories/asset_api.repository.dart';
|
||||
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
||||
import 'package:immich_mobile/repositories/backup.repository.dart';
|
||||
import 'package:immich_mobile/repositories/etag.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
import 'package:immich_mobile/services/album.service.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/backup.service.dart';
|
||||
|
|
@ -45,6 +48,7 @@ final assetServiceProvider = Provider(
|
|||
ref.watch(userServiceProvider),
|
||||
ref.watch(backupServiceProvider),
|
||||
ref.watch(albumServiceProvider),
|
||||
ref.watch(storeServiceProvider),
|
||||
ref.watch(assetMediaRepositoryProvider),
|
||||
),
|
||||
);
|
||||
|
|
@ -61,6 +65,7 @@ class AssetService {
|
|||
final UserService _userService;
|
||||
final BackupService _backupService;
|
||||
final AlbumService _albumService;
|
||||
final StoreService _storeService;
|
||||
final IAssetMediaRepository _assetMediaRepository;
|
||||
final log = Logger('AssetService');
|
||||
|
||||
|
|
@ -76,6 +81,7 @@ class AssetService {
|
|||
this._userService,
|
||||
this._backupService,
|
||||
this._albumService,
|
||||
this._storeService,
|
||||
this._assetMediaRepository,
|
||||
);
|
||||
|
||||
|
|
@ -83,9 +89,9 @@ class AssetService {
|
|||
/// required. Returns `true` if there were any changes.
|
||||
Future<bool> refreshRemoteAssets() async {
|
||||
final syncedUserIds = await _etagRepository.getAllIds();
|
||||
final List<User> syncedUsers = syncedUserIds.isEmpty
|
||||
final List<UserDto> syncedUsers = syncedUserIds.isEmpty
|
||||
? []
|
||||
: await _userRepository.getByIds(syncedUserIds);
|
||||
: (await _userRepository.getByUserIds(syncedUserIds)).nonNulls.toList();
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
final bool changes = await _syncService.syncRemoteAssetsToDb(
|
||||
users: syncedUsers,
|
||||
|
|
@ -99,10 +105,10 @@ class AssetService {
|
|||
|
||||
/// Returns `(null, null)` if changes are invalid -> requires full sync
|
||||
Future<(List<Asset>? toUpsert, List<String>? toDelete)>
|
||||
_getRemoteAssetChanges(List<User> users, DateTime since) async {
|
||||
_getRemoteAssetChanges(List<UserDto> users, DateTime since) async {
|
||||
final dto = AssetDeltaSyncDto(
|
||||
updatedAfter: since,
|
||||
userIds: users.map((e) => e.id).toList(),
|
||||
userIds: users.map((e) => e.uid).toList(),
|
||||
);
|
||||
final changes = await _apiService.syncApi.getDeltaSync(dto);
|
||||
return changes == null || changes.needsFullSync
|
||||
|
|
@ -132,7 +138,7 @@ class AssetService {
|
|||
}
|
||||
|
||||
/// Returns `null` if the server state did not change, else list of assets
|
||||
Future<List<Asset>?> _getRemoteAssets(User user, DateTime until) async {
|
||||
Future<List<Asset>?> _getRemoteAssets(UserDto user, DateTime until) async {
|
||||
const int chunkSize = 10000;
|
||||
try {
|
||||
final List<Asset> allAssets = [];
|
||||
|
|
@ -143,7 +149,7 @@ class AssetService {
|
|||
limit: chunkSize,
|
||||
updatedUntil: until,
|
||||
lastId: lastId,
|
||||
userId: user.id,
|
||||
userId: user.uid,
|
||||
);
|
||||
log.fine("Requesting $chunkSize assets from $lastId");
|
||||
final List<AssetResponseDto>? assets =
|
||||
|
|
@ -314,9 +320,9 @@ class AssetService {
|
|||
);
|
||||
|
||||
await refreshRemoteAssets();
|
||||
final owner = await _userRepository.me();
|
||||
final owner = _storeService.get(StoreKey.currentUser);
|
||||
final remoteAssets = await _assetRepository.getAll(
|
||||
ownerId: owner.isarId,
|
||||
ownerId: owner.id,
|
||||
state: AssetState.merged,
|
||||
);
|
||||
|
||||
|
|
@ -519,13 +525,13 @@ class AssetService {
|
|||
return _assetRepository.watchAsset(id, fireImmediately: fireImmediately);
|
||||
}
|
||||
|
||||
Future<List<Asset>> getRecentlyAddedAssets() async {
|
||||
final me = await _userRepository.me();
|
||||
return _assetRepository.getRecentlyAddedAssets(me.isarId);
|
||||
Future<List<Asset>> getRecentlyAddedAssets() {
|
||||
final me = _storeService.get(StoreKey.currentUser);
|
||||
return _assetRepository.getRecentlyAddedAssets(me.id);
|
||||
}
|
||||
|
||||
Future<List<Asset>> getMotionAssets() async {
|
||||
final me = await _userRepository.me();
|
||||
return _assetRepository.getMotionAssets(me.isarId);
|
||||
Future<List<Asset>> getMotionAssets() {
|
||||
final me = _storeService.get(StoreKey.currentUser);
|
||||
return _assetRepository.getMotionAssets(me.id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@ import 'package:flutter/services.dart';
|
|||
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/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/interfaces/backup_album.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/partner.interface.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
||||
import 'package:immich_mobile/models/backup/error_upload_asset.model.dart';
|
||||
|
|
@ -32,9 +36,9 @@ import 'package:immich_mobile/repositories/backup.repository.dart';
|
|||
import 'package:immich_mobile/repositories/etag.repository.dart';
|
||||
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
||||
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.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';
|
||||
|
|
@ -385,7 +389,7 @@ class BackgroundService {
|
|||
AlbumMediaRepository albumMediaRepository = AlbumMediaRepository();
|
||||
FileMediaRepository fileMediaRepository = FileMediaRepository();
|
||||
AssetMediaRepository assetMediaRepository = AssetMediaRepository();
|
||||
UserRepository userRepository = UserRepository(db);
|
||||
IUserRepository userRepository = IsarUserRepository(db);
|
||||
UserApiRepository userApiRepository =
|
||||
UserApiRepository(apiService.usersApi);
|
||||
AlbumApiRepository albumApiRepository =
|
||||
|
|
@ -396,6 +400,7 @@ class BackgroundService {
|
|||
HashService(assetRepository, this, albumMediaRepository);
|
||||
EntityService entityService =
|
||||
EntityService(assetRepository, userRepository);
|
||||
IPartnerRepository partnerRepository = PartnerRepository(db);
|
||||
SyncService syncSerive = SyncService(
|
||||
hashService,
|
||||
entityService,
|
||||
|
|
@ -404,7 +409,9 @@ class BackgroundService {
|
|||
albumRepository,
|
||||
assetRepository,
|
||||
exifInfoRepository,
|
||||
partnerRepository,
|
||||
userRepository,
|
||||
StoreService.I,
|
||||
eTagRepository,
|
||||
);
|
||||
UserService userService = UserService(
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class BackupVerificationService {
|
|||
|
||||
/// Returns at most [limit] assets that were backed up without exif
|
||||
Future<List<Asset>> findWronglyBackedUpAssets({int limit = 100}) async {
|
||||
final owner = Store.get(StoreKey.currentUser).isarId;
|
||||
final owner = Store.get(StoreKey.currentUser).id;
|
||||
final List<Asset> onlyLocal = await _assetRepository.getAll(
|
||||
ownerId: owner,
|
||||
state: AssetState.local,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
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/infrastructure/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
|
||||
class EntityService {
|
||||
final IAssetRepository _assetRepository;
|
||||
|
|
@ -17,7 +18,8 @@ class EntityService {
|
|||
final ownerId = album.ownerId;
|
||||
if (ownerId != null) {
|
||||
// replace owner with user from database
|
||||
album.owner.value = await _userRepository.get(ownerId);
|
||||
final user = await _userRepository.getByUserId(ownerId);
|
||||
album.owner.value = user == null ? null : User.fromDto(user);
|
||||
}
|
||||
final thumbnailAssetId =
|
||||
album.remoteThumbnailAssetId ?? album.thumbnail.value?.remoteId;
|
||||
|
|
@ -29,9 +31,9 @@ class EntityService {
|
|||
if (album.remoteUsers.isNotEmpty) {
|
||||
// replace all users with users from database
|
||||
final users = await _userRepository
|
||||
.getByIds(album.remoteUsers.map((user) => user.id).toList());
|
||||
.getByUserIds(album.remoteUsers.map((user) => user.id).toList());
|
||||
album.sharedUsers.clear();
|
||||
album.sharedUsers.addAll(users);
|
||||
album.sharedUsers.addAll(users.nonNulls.map(User.fromDto));
|
||||
album.shared = true;
|
||||
}
|
||||
if (album.remoteAssets.isNotEmpty) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.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.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/partner_api.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||
import 'package:immich_mobile/repositories/partner.repository.dart';
|
||||
import 'package:immich_mobile/repositories/partner_api.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
final partnerServiceProvider = Provider(
|
||||
|
|
@ -28,57 +28,58 @@ class PartnerService {
|
|||
this._partnerRepository,
|
||||
);
|
||||
|
||||
Future<List<User>> getSharedWith() async {
|
||||
Future<List<UserDto>> getSharedWith() async {
|
||||
return _partnerRepository.getSharedWith();
|
||||
}
|
||||
|
||||
Future<List<User>> getSharedBy() async {
|
||||
Future<List<UserDto>> getSharedBy() async {
|
||||
return _partnerRepository.getSharedBy();
|
||||
}
|
||||
|
||||
Stream<List<User>> watchSharedWith() {
|
||||
Stream<List<UserDto>> watchSharedWith() {
|
||||
return _partnerRepository.watchSharedWith();
|
||||
}
|
||||
|
||||
Stream<List<User>> watchSharedBy() {
|
||||
Stream<List<UserDto>> watchSharedBy() {
|
||||
return _partnerRepository.watchSharedBy();
|
||||
}
|
||||
|
||||
Future<bool> removePartner(User partner) async {
|
||||
Future<bool> removePartner(UserDto partner) async {
|
||||
try {
|
||||
await _partnerApiRepository.delete(partner.id);
|
||||
partner.isPartnerSharedBy = false;
|
||||
await _userRepository.update(partner);
|
||||
await _partnerApiRepository.delete(partner.uid);
|
||||
await _userRepository.update(partner.copyWith(isPartnerSharedBy: false));
|
||||
} catch (e) {
|
||||
_log.warning("Failed to remove partner ${partner.id}", e);
|
||||
_log.warning("Failed to remove partner ${partner.uid}", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<bool> addPartner(User partner) async {
|
||||
Future<bool> addPartner(UserDto partner) async {
|
||||
try {
|
||||
await _partnerApiRepository.create(partner.id);
|
||||
partner.isPartnerSharedBy = true;
|
||||
await _userRepository.update(partner);
|
||||
await _partnerApiRepository.create(partner.uid);
|
||||
await _userRepository.update(partner.copyWith(isPartnerSharedBy: true));
|
||||
return true;
|
||||
} catch (e) {
|
||||
_log.warning("Failed to add partner ${partner.id}", e);
|
||||
_log.warning("Failed to add partner ${partner.uid}", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> updatePartner(User partner, {required bool inTimeline}) async {
|
||||
Future<bool> updatePartner(
|
||||
UserDto partner, {
|
||||
required bool inTimeline,
|
||||
}) async {
|
||||
try {
|
||||
final dto = await _partnerApiRepository.update(
|
||||
partner.id,
|
||||
partner.uid,
|
||||
inTimeline: inTimeline,
|
||||
);
|
||||
partner.inTimeline = dto.inTimeline;
|
||||
await _userRepository.update(partner);
|
||||
await _userRepository
|
||||
.update(partner.copyWith(inTimeline: dto.inTimeline));
|
||||
return true;
|
||||
} catch (e) {
|
||||
_log.warning("Failed to update partner ${partner.id}", e);
|
||||
_log.warning("Failed to update partner ${partner.uid}", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,24 +3,29 @@ import 'dart:async';
|
|||
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/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/entities/etag.entity.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/extensions/collection_extensions.dart';
|
||||
import 'package:immich_mobile/interfaces/album.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/asset.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/etag.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/partner.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';
|
||||
import 'package:immich_mobile/repositories/album.repository.dart';
|
||||
import 'package:immich_mobile/repositories/album_api.repository.dart';
|
||||
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/user.repository.dart';
|
||||
import 'package:immich_mobile/repositories/partner.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';
|
||||
|
|
@ -37,7 +42,9 @@ final syncServiceProvider = Provider(
|
|||
ref.watch(albumRepositoryProvider),
|
||||
ref.watch(assetRepositoryProvider),
|
||||
ref.watch(exifRepositoryProvider),
|
||||
ref.watch(partnerRepositoryProvider),
|
||||
ref.watch(userRepositoryProvider),
|
||||
ref.watch(storeServiceProvider),
|
||||
ref.watch(etagRepositoryProvider),
|
||||
),
|
||||
);
|
||||
|
|
@ -51,6 +58,8 @@ class SyncService {
|
|||
final IAssetRepository _assetRepository;
|
||||
final IExifInfoRepository _exifInfoRepository;
|
||||
final IUserRepository _userRepository;
|
||||
final IPartnerRepository _partnerRepository;
|
||||
final StoreService _storeService;
|
||||
final IETagRepository _eTagRepository;
|
||||
final AsyncMutex _lock = AsyncMutex();
|
||||
final Logger _log = Logger('SyncService');
|
||||
|
|
@ -63,7 +72,9 @@ class SyncService {
|
|||
this._albumRepository,
|
||||
this._assetRepository,
|
||||
this._exifInfoRepository,
|
||||
this._partnerRepository,
|
||||
this._userRepository,
|
||||
this._storeService,
|
||||
this._eTagRepository,
|
||||
);
|
||||
|
||||
|
|
@ -71,20 +82,20 @@ class SyncService {
|
|||
|
||||
/// Syncs users from the server to the local database
|
||||
/// Returns `true`if there were any changes
|
||||
Future<bool> syncUsersFromServer(List<User> users) =>
|
||||
Future<bool> syncUsersFromServer(List<UserDto> users) =>
|
||||
_lock.run(() => _syncUsersFromServer(users));
|
||||
|
||||
/// Syncs remote assets owned by the logged-in user to the DB
|
||||
/// Returns `true` if there were any changes
|
||||
Future<bool> syncRemoteAssetsToDb({
|
||||
required List<User> users,
|
||||
required List<UserDto> users,
|
||||
required Future<(List<Asset>? toUpsert, List<String>? toDelete)> Function(
|
||||
List<User> users,
|
||||
List<UserDto> users,
|
||||
DateTime since,
|
||||
) getChangedAssets,
|
||||
required FutureOr<List<Asset>?> Function(User user, DateTime until)
|
||||
required FutureOr<List<Asset>?> Function(UserDto user, DateTime until)
|
||||
loadAssets,
|
||||
required FutureOr<List<User>?> Function() refreshUsers,
|
||||
required FutureOr<List<UserDto>?> Function() refreshUsers,
|
||||
}) =>
|
||||
_lock.run(
|
||||
() async =>
|
||||
|
|
@ -134,16 +145,16 @@ class SyncService {
|
|||
|
||||
/// Syncs users from the server to the local database
|
||||
/// Returns `true`if there were any changes
|
||||
Future<bool> _syncUsersFromServer(List<User> users) async {
|
||||
users.sortBy((u) => u.id);
|
||||
final dbUsers = await _userRepository.getAll(sortBy: UserSort.id);
|
||||
Future<bool> _syncUsersFromServer(List<UserDto> users) async {
|
||||
users.sortBy((u) => u.uid);
|
||||
final dbUsers = await _userRepository.getAll(sortBy: SortUserBy.id);
|
||||
final List<int> toDelete = [];
|
||||
final List<User> toUpsert = [];
|
||||
final List<UserDto> toUpsert = [];
|
||||
final changes = diffSortedListsSync(
|
||||
users,
|
||||
dbUsers,
|
||||
compare: (User a, User b) => a.id.compareTo(b.id),
|
||||
both: (User a, User b) {
|
||||
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
|
||||
both: (UserDto a, UserDto b) {
|
||||
if (!a.updatedAt.isAtSameMomentAs(b.updatedAt) ||
|
||||
a.isPartnerSharedBy != b.isPartnerSharedBy ||
|
||||
a.isPartnerSharedWith != b.isPartnerSharedWith ||
|
||||
|
|
@ -153,13 +164,13 @@ class SyncService {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
onlyFirst: (User a) => toUpsert.add(a),
|
||||
onlySecond: (User b) => toDelete.add(b.isarId),
|
||||
onlyFirst: (UserDto a) => toUpsert.add(a),
|
||||
onlySecond: (UserDto b) => toDelete.add(b.id),
|
||||
);
|
||||
if (changes) {
|
||||
await _userRepository.transaction(() async {
|
||||
await _userRepository.deleteById(toDelete);
|
||||
await _userRepository.upsertAll(toUpsert);
|
||||
await _userRepository.delete(toDelete);
|
||||
await _userRepository.updateAll(toUpsert);
|
||||
});
|
||||
}
|
||||
return changes;
|
||||
|
|
@ -185,15 +196,15 @@ class SyncService {
|
|||
|
||||
/// Efficiently syncs assets via changes. Returns `null` when a full sync is required.
|
||||
Future<bool?> _syncRemoteAssetChanges(
|
||||
List<User> users,
|
||||
List<UserDto> users,
|
||||
Future<(List<Asset>? toUpsert, List<String>? toDelete)> Function(
|
||||
List<User> users,
|
||||
List<UserDto> users,
|
||||
DateTime since,
|
||||
) getChangedAssets,
|
||||
) async {
|
||||
final currentUser = await _userRepository.me();
|
||||
final currentUser = _storeService.get(StoreKey.currentUser);
|
||||
final DateTime? since =
|
||||
(await _eTagRepository.get(currentUser.isarId))?.time?.toUtc();
|
||||
(await _eTagRepository.get(currentUser.id))?.time?.toUtc();
|
||||
if (since == null) return null;
|
||||
final DateTime now = DateTime.now();
|
||||
final (toUpsert, toDelete) = await getChangedAssets(users, since);
|
||||
|
|
@ -240,10 +251,16 @@ class SyncService {
|
|||
});
|
||||
}
|
||||
|
||||
Future<List<UserDto>> _getAllAccessibleUsers() async {
|
||||
final sharedWith = (await _partnerRepository.getSharedWith()).toSet();
|
||||
sharedWith.add(_storeService.get(StoreKey.currentUser));
|
||||
return sharedWith.toList();
|
||||
}
|
||||
|
||||
/// Syncs assets by loading and comparing all assets from the server.
|
||||
Future<bool> _syncRemoteAssetsFull(
|
||||
FutureOr<List<User>?> Function() refreshUsers,
|
||||
FutureOr<List<Asset>?> Function(User user, DateTime until) loadAssets,
|
||||
FutureOr<List<UserDto>?> Function() refreshUsers,
|
||||
FutureOr<List<Asset>?> Function(UserDto user, DateTime until) loadAssets,
|
||||
) async {
|
||||
final serverUsers = await refreshUsers();
|
||||
if (serverUsers == null) {
|
||||
|
|
@ -251,17 +268,17 @@ class SyncService {
|
|||
return false;
|
||||
}
|
||||
await _syncUsersFromServer(serverUsers);
|
||||
final List<User> users = await _userRepository.getAllAccessible();
|
||||
final List<UserDto> users = await _getAllAccessibleUsers();
|
||||
bool changes = false;
|
||||
for (User u in users) {
|
||||
for (UserDto u in users) {
|
||||
changes |= await _syncRemoteAssetsForUser(u, loadAssets);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
Future<bool> _syncRemoteAssetsForUser(
|
||||
User user,
|
||||
FutureOr<List<Asset>?> Function(User user, DateTime until) loadAssets,
|
||||
UserDto user,
|
||||
FutureOr<List<Asset>?> Function(UserDto user, DateTime until) loadAssets,
|
||||
) async {
|
||||
final DateTime now = DateTime.now().toUtc();
|
||||
final List<Asset>? remote = await loadAssets(user, now);
|
||||
|
|
@ -269,7 +286,7 @@ class SyncService {
|
|||
return false;
|
||||
}
|
||||
final List<Asset> inDb = await _assetRepository.getAll(
|
||||
ownerId: user.isarId,
|
||||
ownerId: user.id,
|
||||
sortBy: AssetSort.checksum,
|
||||
);
|
||||
assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!");
|
||||
|
|
@ -295,13 +312,13 @@ class SyncService {
|
|||
return true;
|
||||
}
|
||||
|
||||
Future<void> _updateUserAssetsETag(List<User> users, DateTime time) {
|
||||
final etags = users.map((u) => ETag(id: u.id, time: time)).toList();
|
||||
Future<void> _updateUserAssetsETag(List<UserDto> users, DateTime time) {
|
||||
final etags = users.map((u) => ETag(id: u.uid, time: time)).toList();
|
||||
return _eTagRepository.upsertAll(etags);
|
||||
}
|
||||
|
||||
Future<void> _clearUserAssetsETag(List<User> users) {
|
||||
final ids = users.map((u) => u.id).toList();
|
||||
Future<void> _clearUserAssetsETag(List<UserDto> users) {
|
||||
final ids = users.map((u) => u.uid).toList();
|
||||
return _eTagRepository.deleteByIds(ids);
|
||||
}
|
||||
|
||||
|
|
@ -373,26 +390,27 @@ class SyncService {
|
|||
);
|
||||
|
||||
// update shared users
|
||||
final List<User> sharedUsers = album.sharedUsers.toList(growable: false);
|
||||
final List<UserDto> sharedUsers =
|
||||
album.sharedUsers.map((u) => u.toDto()).toList(growable: false);
|
||||
sharedUsers.sort((a, b) => a.id.compareTo(b.id));
|
||||
final List<User> users = dto.remoteUsers.toList()
|
||||
final List<UserDto> users = dto.remoteUsers.map((u) => u.toDto()).toList()
|
||||
..sort((a, b) => a.id.compareTo(b.id));
|
||||
final List<String> userIdsToAdd = [];
|
||||
final List<User> usersToUnlink = [];
|
||||
final List<UserDto> usersToUnlink = [];
|
||||
diffSortedListsSync(
|
||||
users,
|
||||
sharedUsers,
|
||||
compare: (User a, User b) => a.id.compareTo(b.id),
|
||||
compare: (UserDto a, UserDto b) => a.id.compareTo(b.id),
|
||||
both: (a, b) => false,
|
||||
onlyFirst: (User a) => userIdsToAdd.add(a.id),
|
||||
onlySecond: (User a) => usersToUnlink.add(a),
|
||||
onlyFirst: (UserDto a) => userIdsToAdd.add(a.uid),
|
||||
onlySecond: (UserDto a) => usersToUnlink.add(a),
|
||||
);
|
||||
|
||||
// for shared album: put missing album assets into local DB
|
||||
final (existingInDb, updated) = await _linkWithExistingFromDb(toAdd);
|
||||
await upsertAssetsWithExif(updated);
|
||||
final assetsToLink = existingInDb + updated;
|
||||
final usersToLink = await _userRepository.getByIds(userIdsToAdd);
|
||||
final usersToLink = await _userRepository.getByUserIds(userIdsToAdd);
|
||||
|
||||
album.name = dto.name;
|
||||
album.shared = dto.shared;
|
||||
|
|
@ -416,7 +434,7 @@ class SyncService {
|
|||
try {
|
||||
await _assetRepository.transaction(() async {
|
||||
await _assetRepository.updateAll(toUpdate);
|
||||
await _albumRepository.addUsers(album, usersToLink);
|
||||
await _albumRepository.addUsers(album, usersToLink.nonNulls.toList());
|
||||
await _albumRepository.removeUsers(album, usersToUnlink);
|
||||
await _albumRepository.addAssets(album, assetsToLink);
|
||||
await _albumRepository.removeAssets(album, toUnlink);
|
||||
|
|
@ -429,7 +447,7 @@ class SyncService {
|
|||
}
|
||||
|
||||
if (album.shared || dto.shared) {
|
||||
final userId = (await _userRepository.me()).isarId;
|
||||
final userId = (_storeService.get(StoreKey.currentUser)).id;
|
||||
final foreign =
|
||||
await _assetRepository.getByAlbum(album, notOwnedBy: [userId]);
|
||||
existing.addAll(foreign);
|
||||
|
|
@ -482,8 +500,7 @@ class SyncService {
|
|||
);
|
||||
} else if (album.shared) {
|
||||
// delete assets in DB unless they belong to this user or are part of some other shared album or belong to a partner
|
||||
final userIds =
|
||||
(await _userRepository.getAllAccessible()).map((user) => user.isarId);
|
||||
final userIds = (await _getAllAccessibleUsers()).map((user) => user.id);
|
||||
final orphanedAssets =
|
||||
await _assetRepository.getByAlbum(album, notOwnedBy: userIds);
|
||||
deleteCandidates.addAll(orphanedAssets);
|
||||
|
|
@ -566,7 +583,7 @@ class SyncService {
|
|||
// general case, e.g. some assets have been deleted or there are excluded albums on iOS
|
||||
final inDb = await _assetRepository.getByAlbum(
|
||||
dbAlbum,
|
||||
ownerId: (await _userRepository.me()).isarId,
|
||||
ownerId: (_storeService.get(StoreKey.currentUser)).id,
|
||||
sortBy: AssetSort.checksum,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,41 +1,42 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/timeline.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
|
||||
import 'package:immich_mobile/repositories/timeline.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
||||
|
||||
final timelineServiceProvider = Provider<TimelineService>((ref) {
|
||||
return TimelineService(
|
||||
ref.watch(timelineRepositoryProvider),
|
||||
ref.watch(userRepositoryProvider),
|
||||
ref.watch(appSettingsServiceProvider),
|
||||
ref.watch(storeServiceProvider),
|
||||
);
|
||||
});
|
||||
|
||||
class TimelineService {
|
||||
final ITimelineRepository _timelineRepository;
|
||||
final IUserRepository _userRepository;
|
||||
final AppSettingsService _appSettingsService;
|
||||
final StoreService _storeService;
|
||||
|
||||
const TimelineService(
|
||||
this._timelineRepository,
|
||||
this._userRepository,
|
||||
this._appSettingsService,
|
||||
this._storeService,
|
||||
);
|
||||
|
||||
Future<List<int>> getTimelineUserIds() async {
|
||||
final me = await _userRepository.me();
|
||||
return _timelineRepository.getTimelineUserIds(me.isarId);
|
||||
final me = _storeService.get(StoreKey.currentUser);
|
||||
return _timelineRepository.getTimelineUserIds(me.id);
|
||||
}
|
||||
|
||||
Stream<List<int>> watchTimelineUserIds() async* {
|
||||
final me = await _userRepository.me();
|
||||
yield* _timelineRepository.watchTimelineUsers(me.isarId);
|
||||
final me = _storeService.get(StoreKey.currentUser);
|
||||
yield* _timelineRepository.watchTimelineUsers(me.id);
|
||||
}
|
||||
|
||||
Stream<RenderList> watchHomeTimeline(int userId) {
|
||||
|
|
@ -50,15 +51,15 @@ class TimelineService {
|
|||
}
|
||||
|
||||
Stream<RenderList> watchArchiveTimeline() async* {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
yield* _timelineRepository.watchArchiveTimeline(user.isarId);
|
||||
yield* _timelineRepository.watchArchiveTimeline(user.id);
|
||||
}
|
||||
|
||||
Stream<RenderList> watchFavoriteTimeline() async* {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
yield* _timelineRepository.watchFavoriteTimeline(user.isarId);
|
||||
yield* _timelineRepository.watchFavoriteTimeline(user.id);
|
||||
}
|
||||
|
||||
Stream<RenderList> watchAlbumTimeline(Album album) async* {
|
||||
|
|
@ -69,9 +70,9 @@ class TimelineService {
|
|||
}
|
||||
|
||||
Stream<RenderList> watchTrashTimeline() async* {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
yield* _timelineRepository.watchTrashTimeline(user.isarId);
|
||||
yield* _timelineRepository.watchTrashTimeline(user.id);
|
||||
}
|
||||
|
||||
Stream<RenderList> watchAllVideosTimeline() {
|
||||
|
|
@ -96,9 +97,9 @@ class TimelineService {
|
|||
}
|
||||
|
||||
Stream<RenderList> watchAssetSelectionTimeline() async* {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
yield* _timelineRepository.watchAssetSelectionTimeline(user.isarId);
|
||||
yield* _timelineRepository.watchAssetSelectionTimeline(user.id);
|
||||
}
|
||||
|
||||
GroupAssetsBy _getGroupByOption() {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||
import 'package:immich_mobile/interfaces/user.interface.dart';
|
||||
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
|
||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user.repository.dart';
|
||||
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
|
|
@ -14,16 +13,20 @@ final trashServiceProvider = Provider<TrashService>((ref) {
|
|||
return TrashService(
|
||||
ref.watch(apiServiceProvider),
|
||||
ref.watch(assetRepositoryProvider),
|
||||
ref.watch(userRepositoryProvider),
|
||||
ref.watch(storeServiceProvider),
|
||||
);
|
||||
});
|
||||
|
||||
class TrashService {
|
||||
final ApiService _apiService;
|
||||
final IAssetRepository _assetRepository;
|
||||
final IUserRepository _userRepository;
|
||||
final StoreService _storeService;
|
||||
|
||||
TrashService(this._apiService, this._assetRepository, this._userRepository);
|
||||
TrashService(
|
||||
this._apiService,
|
||||
this._assetRepository,
|
||||
this._storeService,
|
||||
);
|
||||
|
||||
Future<void> restoreAssets(Iterable<Asset> assetList) async {
|
||||
final remoteAssets = assetList.where((a) => a.isRemote);
|
||||
|
|
@ -40,11 +43,11 @@ class TrashService {
|
|||
}
|
||||
|
||||
Future<void> emptyTrash() async {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
await _apiService.trashApi.emptyTrash();
|
||||
|
||||
final trashedAssets = await _assetRepository.getTrashAssets(user.isarId);
|
||||
final trashedAssets = await _assetRepository.getTrashAssets(user.id);
|
||||
final ids = trashedAssets.map((e) => e.remoteId!).toList();
|
||||
|
||||
await _assetRepository.transaction(() async {
|
||||
|
|
@ -71,11 +74,11 @@ class TrashService {
|
|||
}
|
||||
|
||||
Future<void> restoreTrash() async {
|
||||
final user = await _userRepository.me();
|
||||
final user = _storeService.get(StoreKey.currentUser);
|
||||
|
||||
await _apiService.trashApi.restoreTrash();
|
||||
|
||||
final trashedAssets = await _assetRepository.getTrashAssets(user.isarId);
|
||||
final trashedAssets = await _assetRepository.getTrashAssets(user.id);
|
||||
final updatedAssets = trashedAssets.map((asset) {
|
||||
asset.isTrashed = false;
|
||||
return asset;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.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.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.repository.dart';
|
||||
import 'package:immich_mobile/repositories/user_api.repository.dart';
|
||||
import 'package:immich_mobile/utils/diff.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
|
@ -31,10 +31,6 @@ class UserService {
|
|||
this._userRepository,
|
||||
);
|
||||
|
||||
Future<List<User>> getUsers({bool self = false}) {
|
||||
return _userRepository.getAll(self: self);
|
||||
}
|
||||
|
||||
Future<({String profileImagePath})?> uploadProfileImage(XFile image) async {
|
||||
try {
|
||||
return await _userApiRepository.createProfileImage(
|
||||
|
|
@ -47,17 +43,21 @@ class UserService {
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<User>?> getUsersFromServer() async {
|
||||
List<User>? users;
|
||||
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<User> sharedBy =
|
||||
final List<UserDto> sharedBy =
|
||||
await _partnerApiRepository.getAll(Direction.sharedByMe);
|
||||
final List<User> sharedWith =
|
||||
final List<UserDto> sharedWith =
|
||||
await _partnerApiRepository.getAll(Direction.sharedWithMe);
|
||||
|
||||
if (users == null) {
|
||||
|
|
@ -65,36 +65,44 @@ class UserService {
|
|||
return null;
|
||||
}
|
||||
|
||||
users.sortBy((u) => u.id);
|
||||
sharedBy.sortBy((u) => u.id);
|
||||
sharedWith.sortBy((u) => u.id);
|
||||
users.sortBy((u) => u.uid);
|
||||
sharedBy.sortBy((u) => u.uid);
|
||||
sharedWith.sortBy((u) => u.uid);
|
||||
|
||||
final updatedSharedBy = <UserDto>[];
|
||||
|
||||
diffSortedListsSync(
|
||||
users,
|
||||
sharedBy,
|
||||
compare: (User a, User b) => a.id.compareTo(b.id),
|
||||
both: (User a, User b) => a.isPartnerSharedBy = true,
|
||||
onlyFirst: (_) {},
|
||||
onlySecond: (_) {},
|
||||
);
|
||||
|
||||
diffSortedListsSync(
|
||||
users,
|
||||
sharedWith,
|
||||
compare: (User a, User b) => a.id.compareTo(b.id),
|
||||
both: (User a, User b) {
|
||||
a.isPartnerSharedWith = true;
|
||||
a.inTimeline = b.inTimeline;
|
||||
compare: (UserDto a, UserDto b) => a.uid.compareTo(b.uid),
|
||||
both: (UserDto a, UserDto b) {
|
||||
updatedSharedBy.add(a.copyWith(isPartnerSharedBy: true));
|
||||
return true;
|
||||
},
|
||||
onlyFirst: (_) {},
|
||||
onlySecond: (_) {},
|
||||
onlyFirst: (UserDto a) => updatedSharedBy.add(a),
|
||||
onlySecond: (UserDto b) => updatedSharedBy.add(b),
|
||||
);
|
||||
|
||||
return users;
|
||||
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.clearTable();
|
||||
return _userRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue