From 4db8f0c66646ad60b273340cc4e0cd6e1a8b34d6 Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:40:09 +0530 Subject: [PATCH] refactor(mobile): move timeline methods to timeline repo (#16526) * refactor: move timeline calls to timeline repo * refactor: review changes --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> --- mobile/lib/interfaces/timeline.interface.dart | 4 ++++ mobile/lib/interfaces/user.interface.dart | 4 ---- mobile/lib/providers/asset.provider.dart | 6 ++++- mobile/lib/providers/user.provider.dart | 15 ++++++------ .../lib/repositories/timeline.repository.dart | 23 +++++++++++++++++++ mobile/lib/repositories/user.repository.dart | 22 ------------------ mobile/lib/services/album.service.dart | 5 +++- mobile/lib/services/background.service.dart | 1 - mobile/lib/services/sync.service.dart | 2 +- mobile/lib/services/timeline.service.dart | 13 ++++++++++- mobile/lib/services/user.service.dart | 22 +----------------- mobile/test/services/album.service_test.dart | 8 +++++-- 12 files changed, 64 insertions(+), 61 deletions(-) diff --git a/mobile/lib/interfaces/timeline.interface.dart b/mobile/lib/interfaces/timeline.interface.dart index 78b1a22111e..d43f87ed5b6 100644 --- a/mobile/lib/interfaces/timeline.interface.dart +++ b/mobile/lib/interfaces/timeline.interface.dart @@ -3,6 +3,10 @@ import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart'; abstract class ITimelineRepository { + Future> getTimelineUserIds(int id); + + Stream> watchTimelineUsers(int id); + Stream watchArchiveTimeline(int userId); Stream watchFavoriteTimeline(int userId); Stream watchTrashTimeline(int userId); diff --git a/mobile/lib/interfaces/user.interface.dart b/mobile/lib/interfaces/user.interface.dart index 17918ac1701..d099e0e50b0 100644 --- a/mobile/lib/interfaces/user.interface.dart +++ b/mobile/lib/interfaces/user.interface.dart @@ -22,10 +22,6 @@ abstract interface class IUserRepository implements IDatabaseRepository { Future me(); Future clearTable(); - - Future> getTimelineUserIds(int id); - - Stream> watchTimelineUsers(int id); } enum UserSort { id } diff --git a/mobile/lib/providers/asset.provider.dart b/mobile/lib/providers/asset.provider.dart index 8d5209ccb7b..f093d90071e 100644 --- a/mobile/lib/providers/asset.provider.dart +++ b/mobile/lib/providers/asset.provider.dart @@ -59,7 +59,11 @@ class AssetNotifier extends StateNotifier { await clearAllAssets(); log.info("Manual refresh requested, cleared assets and albums from db"); } - final bool changedUsers = await _userService.refreshUsers(); + final users = await _userService.getUsersFromServer(); + bool changedUsers = false; + if (users != null) { + changedUsers = await _syncService.syncUsersFromServer(users); + } final bool newRemote = await _assetService.refreshRemoteAssets(); final bool newLocal = await _albumService.refreshDeviceAlbums(); debugPrint( diff --git a/mobile/lib/providers/user.provider.dart b/mobile/lib/providers/user.provider.dart index c143086a156..0a1bc0275a6 100644 --- a/mobile/lib/providers/user.provider.dart +++ b/mobile/lib/providers/user.provider.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; -import 'package:immich_mobile/services/user.service.dart'; +import 'package:immich_mobile/services/timeline.service.dart'; class CurrentUserProvider extends StateNotifier { CurrentUserProvider(this._apiService) : super(null) { @@ -46,14 +46,15 @@ final currentUserProvider = }); class TimelineUserIdsProvider extends StateNotifier> { - TimelineUserIdsProvider(this._userService) : super([]) { - _userService.getTimelineUserIds().then((users) => state = users); - streamSub = - _userService.watchTimelineUserIds().listen((users) => state = users); + TimelineUserIdsProvider(this._timelineService) : super([]) { + _timelineService.getTimelineUserIds().then((users) => state = users); + streamSub = _timelineService + .watchTimelineUserIds() + .listen((users) => state = users); } late final StreamSubscription> streamSub; - final UserService _userService; + final TimelineService _timelineService; @override void dispose() { @@ -64,5 +65,5 @@ class TimelineUserIdsProvider extends StateNotifier> { final timelineUsersIdsProvider = StateNotifierProvider>((ref) { - return TimelineUserIdsProvider(ref.watch(userServiceProvider)); + return TimelineUserIdsProvider(ref.watch(timelineServiceProvider)); }); diff --git a/mobile/lib/repositories/timeline.repository.dart b/mobile/lib/repositories/timeline.repository.dart index d1abaaf3a5e..1b9ee8ad37d 100644 --- a/mobile/lib/repositories/timeline.repository.dart +++ b/mobile/lib/repositories/timeline.repository.dart @@ -2,6 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/interfaces/timeline.interface.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/repositories/database.repository.dart'; @@ -15,6 +16,28 @@ class TimelineRepository extends DatabaseRepository implements ITimelineRepository { TimelineRepository(super.db); + @override + Future> getTimelineUserIds(int id) { + return db.users + .filter() + .inTimelineEqualTo(true) + .or() + .isarIdEqualTo(id) + .isarIdProperty() + .findAll(); + } + + @override + Stream> watchTimelineUsers(int id) { + return db.users + .filter() + .inTimelineEqualTo(true) + .or() + .isarIdEqualTo(id) + .isarIdProperty() + .watch(); + } + @override Stream watchArchiveTimeline(int userId) { final query = db.assets diff --git a/mobile/lib/repositories/user.repository.dart b/mobile/lib/repositories/user.repository.dart index 190fb780c8f..ea67b30e0d7 100644 --- a/mobile/lib/repositories/user.repository.dart +++ b/mobile/lib/repositories/user.repository.dart @@ -70,26 +70,4 @@ class UserRepository extends DatabaseRepository implements IUserRepository { await db.users.clear(); }); } - - @override - Future> getTimelineUserIds(int id) { - return db.users - .filter() - .inTimelineEqualTo(true) - .or() - .isarIdEqualTo(id) - .isarIdProperty() - .findAll(); - } - - @override - Stream> watchTimelineUsers(int id) { - return db.users - .filter() - .inTimelineEqualTo(true) - .or() - .isarIdEqualTo(id) - .isarIdProperty() - .watch(); - } } diff --git a/mobile/lib/services/album.service.dart b/mobile/lib/services/album.service.dart index 9c1f25f0a5e..3a44ca72862 100644 --- a/mobile/lib/services/album.service.dart +++ b/mobile/lib/services/album.service.dart @@ -169,7 +169,10 @@ class AlbumService { final Stopwatch sw = Stopwatch()..start(); bool changes = false; try { - await _userService.refreshUsers(); + final users = await _userService.getUsersFromServer(); + if (users != null) { + await _syncService.syncUsersFromServer(users); + } final (sharedAlbum, ownedAlbum) = await ( // Note: `shared: true` is required to get albums that don't belong to // us due to unusual behaviour on the API but this will also return our diff --git a/mobile/lib/services/background.service.dart b/mobile/lib/services/background.service.dart index e457102d9f4..81832825866 100644 --- a/mobile/lib/services/background.service.dart +++ b/mobile/lib/services/background.service.dart @@ -410,7 +410,6 @@ class BackgroundService { partnerApiRepository, userApiRepository, userRepository, - syncSerive, ); AlbumService albumService = AlbumService( userService, diff --git a/mobile/lib/services/sync.service.dart b/mobile/lib/services/sync.service.dart index 34df4618662..d01a49a38da 100644 --- a/mobile/lib/services/sync.service.dart +++ b/mobile/lib/services/sync.service.dart @@ -6,6 +6,7 @@ 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'; @@ -23,7 +24,6 @@ import 'package:immich_mobile/repositories/user.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'; -import 'package:immich_mobile/extensions/collection_extensions.dart'; import 'package:immich_mobile/utils/datetime_comparison.dart'; import 'package:immich_mobile/utils/diff.dart'; import 'package:logging/logging.dart'; diff --git a/mobile/lib/services/timeline.service.dart b/mobile/lib/services/timeline.service.dart index a89377548fe..db85230662b 100644 --- a/mobile/lib/services/timeline.service.dart +++ b/mobile/lib/services/timeline.service.dart @@ -21,12 +21,23 @@ class TimelineService { final ITimelineRepository _timelineRepository; final IUserRepository _userRepository; final AppSettingsService _appSettingsService; - TimelineService( + + const TimelineService( this._timelineRepository, this._userRepository, this._appSettingsService, ); + Future> getTimelineUserIds() async { + final me = await _userRepository.me(); + return _timelineRepository.getTimelineUserIds(me.isarId); + } + + Stream> watchTimelineUserIds() async* { + final me = await _userRepository.me(); + yield* _timelineRepository.watchTimelineUsers(me.isarId); + } + Stream watchHomeTimeline(int userId) { return _timelineRepository.watchHomeTimeline(userId, _getGroupByOption()); } diff --git a/mobile/lib/services/user.service.dart b/mobile/lib/services/user.service.dart index a14b1c08f2f..921202ec59f 100644 --- a/mobile/lib/services/user.service.dart +++ b/mobile/lib/services/user.service.dart @@ -1,14 +1,13 @@ 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/interfaces/partner_api.interface.dart'; import 'package:immich_mobile/interfaces/user.interface.dart'; import 'package:immich_mobile/interfaces/user_api.interface.dart'; import 'package:immich_mobile/repositories/partner_api.repository.dart'; import 'package:immich_mobile/repositories/user.repository.dart'; import 'package:immich_mobile/repositories/user_api.repository.dart'; -import 'package:immich_mobile/entities/user.entity.dart'; -import 'package:immich_mobile/services/sync.service.dart'; import 'package:immich_mobile/utils/diff.dart'; import 'package:logging/logging.dart'; @@ -17,7 +16,6 @@ final userServiceProvider = Provider( ref.watch(partnerApiRepositoryProvider), ref.watch(userApiRepositoryProvider), ref.watch(userRepositoryProvider), - ref.watch(syncServiceProvider), ), ); @@ -25,14 +23,12 @@ class UserService { final IPartnerApiRepository _partnerApiRepository; final IUserApiRepository _userApiRepository; final IUserRepository _userRepository; - final SyncService _syncService; final Logger _log = Logger("UserService"); UserService( this._partnerApiRepository, this._userApiRepository, this._userRepository, - this._syncService, ); Future> getUsers({bool self = false}) { @@ -98,23 +94,7 @@ class UserService { return users; } - Future refreshUsers() async { - final users = await getUsersFromServer(); - if (users == null) return false; - return _syncService.syncUsersFromServer(users); - } - Future clearTable() { return _userRepository.clearTable(); } - - Future> getTimelineUserIds() async { - final me = await _userRepository.me(); - return _userRepository.getTimelineUserIds(me.isarId); - } - - Stream> watchTimelineUserIds() async* { - final me = await _userRepository.me(); - yield* _userRepository.watchTimelineUsers(me.isarId); - } } diff --git a/mobile/test/services/album.service_test.dart b/mobile/test/services/album.service_test.dart index c0775a1c3e0..983b355dcb3 100644 --- a/mobile/test/services/album.service_test.dart +++ b/mobile/test/services/album.service_test.dart @@ -2,6 +2,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:immich_mobile/entities/backup_album.entity.dart'; import 'package:immich_mobile/services/album.service.dart'; import 'package:mocktail/mocktail.dart'; + import '../fixtures/album.stub.dart'; import '../fixtures/asset.stub.dart'; import '../fixtures/user.stub.dart'; @@ -83,7 +84,9 @@ void main() { group('refreshRemoteAlbums', () { test('is working', () async { - when(() => userService.refreshUsers()).thenAnswer((_) async => true); + when(() => userService.getUsersFromServer()).thenAnswer((_) async => []); + when(() => syncService.syncUsersFromServer(any())) + .thenAnswer((_) async => true); when(() => albumApiRepository.getAll(shared: true)) .thenAnswer((_) async => [AlbumStub.sharedWithUser]); @@ -99,7 +102,8 @@ void main() { ).thenAnswer((_) async => true); final result = await sut.refreshRemoteAlbums(); expect(result, true); - verify(() => userService.refreshUsers()).called(1); + verify(() => userService.getUsersFromServer()).called(1); + verify(() => syncService.syncUsersFromServer([])).called(1); verify(() => albumApiRepository.getAll(shared: true)).called(1); verify(() => albumApiRepository.getAll(shared: null)).called(1); verify(