mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
refactor(mobile): use user service methods (#16783)
* refactor: user entity * chore: rebase fixes * refactor(mobile): refactor to use user service methods * fix: late init error * fix: lint --------- 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
6c2985df26
commit
dd263b010c
@ -44,10 +44,14 @@ class UserService {
|
|||||||
|
|
||||||
Future<String?> createProfileImage(String name, Uint8List image) async {
|
Future<String?> createProfileImage(String name, Uint8List image) async {
|
||||||
try {
|
try {
|
||||||
return await _userApiRepository.createProfileImage(
|
final path = await _userApiRepository.createProfileImage(
|
||||||
name: name,
|
name: name,
|
||||||
data: image,
|
data: image,
|
||||||
);
|
);
|
||||||
|
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
||||||
|
await _storeService.put(StoreKey.currentUser, updatedUser);
|
||||||
|
await _userRepository.update(updatedUser);
|
||||||
|
return path;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("Failed to upload profile image", e);
|
_log.warning("Failed to upload profile image", e);
|
||||||
return null;
|
return null;
|
||||||
|
@ -3,11 +3,12 @@ import 'package:flutter_udid/flutter_udid.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.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/user.service.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
|
||||||
import 'package:immich_mobile/models/auth/auth_state.model.dart';
|
import 'package:immich_mobile/models/auth/auth_state.model.dart';
|
||||||
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:immich_mobile/services/auth.service.dart';
|
import 'package:immich_mobile/services/auth.service.dart';
|
||||||
import 'package:immich_mobile/utils/hash.dart';
|
import 'package:immich_mobile/utils/hash.dart';
|
||||||
@ -18,20 +19,20 @@ final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
|
|||||||
return AuthNotifier(
|
return AuthNotifier(
|
||||||
ref.watch(authServiceProvider),
|
ref.watch(authServiceProvider),
|
||||||
ref.watch(apiServiceProvider),
|
ref.watch(apiServiceProvider),
|
||||||
|
ref.watch(userServiceProvider),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
class AuthNotifier extends StateNotifier<AuthState> {
|
class AuthNotifier extends StateNotifier<AuthState> {
|
||||||
final AuthService _authService;
|
final AuthService _authService;
|
||||||
final ApiService _apiService;
|
final ApiService _apiService;
|
||||||
|
final UserService _userService;
|
||||||
final _log = Logger("AuthenticationNotifier");
|
final _log = Logger("AuthenticationNotifier");
|
||||||
|
|
||||||
static const Duration _timeoutDuration = Duration(seconds: 7);
|
static const Duration _timeoutDuration = Duration(seconds: 7);
|
||||||
|
|
||||||
AuthNotifier(
|
AuthNotifier(this._authService, this._apiService, this._userService)
|
||||||
this._authService,
|
: super(
|
||||||
this._apiService,
|
|
||||||
) : super(
|
|
||||||
AuthState(
|
AuthState(
|
||||||
deviceId: "",
|
deviceId: "",
|
||||||
userId: "",
|
userId: "",
|
||||||
@ -106,17 +107,21 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
String deviceId =
|
String deviceId =
|
||||||
Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid;
|
Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid;
|
||||||
|
|
||||||
UserDto? user = Store.tryGet(StoreKey.currentUser);
|
UserDto? user = _userService.tryGetMyUser();
|
||||||
|
|
||||||
UserAdminResponseDto? userResponse;
|
|
||||||
UserPreferencesResponseDto? userPreferences;
|
|
||||||
try {
|
try {
|
||||||
final responses = await Future.wait([
|
final serverUser =
|
||||||
_apiService.usersApi.getMyUser().timeout(_timeoutDuration),
|
await _userService.refreshMyUser().timeout(_timeoutDuration);
|
||||||
_apiService.usersApi.getMyPreferences().timeout(_timeoutDuration),
|
if (serverUser == null) {
|
||||||
]);
|
_log.severe("Unable to get user information from the server.");
|
||||||
userResponse = responses[0] as UserAdminResponseDto;
|
} else {
|
||||||
userPreferences = responses[1] as UserPreferencesResponseDto;
|
// If the user information is successfully retrieved, update the store
|
||||||
|
// Due to the flow of the code, this will always happen on first login
|
||||||
|
user = serverUser;
|
||||||
|
await Store.put(StoreKey.deviceId, deviceId);
|
||||||
|
await Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
|
||||||
|
await Store.put(StoreKey.accessToken, accessToken);
|
||||||
|
}
|
||||||
} on ApiException catch (error, stackTrace) {
|
} on ApiException catch (error, stackTrace) {
|
||||||
if (error.code == 401) {
|
if (error.code == 401) {
|
||||||
_log.severe("Unauthorized access, token likely expired. Logging out.");
|
_log.severe("Unauthorized access, token likely expired. Logging out.");
|
||||||
@ -140,22 +145,6 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user information is successfully retrieved, update the store
|
|
||||||
// Due to the flow of the code, this will always happen on first login
|
|
||||||
if (userResponse == null) {
|
|
||||||
_log.severe("Unable to get user information from the server.");
|
|
||||||
} else {
|
|
||||||
await Store.put(StoreKey.deviceId, deviceId);
|
|
||||||
await Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
|
|
||||||
await Store.put(
|
|
||||||
StoreKey.currentUser,
|
|
||||||
UserConverter.fromAdminDto(userResponse, userPreferences),
|
|
||||||
);
|
|
||||||
await Store.put(StoreKey.accessToken, accessToken);
|
|
||||||
|
|
||||||
user = UserConverter.fromAdminDto(userResponse, userPreferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user is null, the login was not successful
|
// If the user is null, the login was not successful
|
||||||
// and we don't have a local copy of the user from a prior successful login
|
// and we don't have a local copy of the user from a prior successful login
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
@ -163,13 +152,13 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
isAuthenticated: true,
|
deviceId: deviceId,
|
||||||
userId: user.uid,
|
userId: user.uid,
|
||||||
userEmail: user.email,
|
userEmail: user.email,
|
||||||
|
isAuthenticated: true,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
profileImagePath: user.profileImagePath,
|
|
||||||
isAdmin: user.isAdmin,
|
isAdmin: user.isAdmin,
|
||||||
deviceId: deviceId,
|
profileImagePath: user.profileImagePath,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,34 +1,24 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.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/entities/store.entity.dart';
|
import 'package:immich_mobile/domain/services/user.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
|
||||||
import 'package:immich_mobile/services/timeline.service.dart';
|
import 'package:immich_mobile/services/timeline.service.dart';
|
||||||
|
|
||||||
class CurrentUserProvider extends StateNotifier<UserDto?> {
|
class CurrentUserProvider extends StateNotifier<UserDto?> {
|
||||||
CurrentUserProvider(this._apiService) : super(null) {
|
CurrentUserProvider(this._userService) : super(null) {
|
||||||
state = Store.tryGet(StoreKey.currentUser);
|
state = _userService.tryGetMyUser();
|
||||||
streamSub =
|
streamSub =
|
||||||
Store.watch(StoreKey.currentUser).listen((user) => state = user);
|
_userService.watchMyUser().listen((user) => state = user ?? state);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ApiService _apiService;
|
final UserService _userService;
|
||||||
late final StreamSubscription<UserDto?> streamSub;
|
late final StreamSubscription<UserDto?> streamSub;
|
||||||
|
|
||||||
refresh() async {
|
refresh() async {
|
||||||
try {
|
try {
|
||||||
final user = await _apiService.usersApi.getMyUser();
|
await _userService.refreshMyUser();
|
||||||
final userPreferences = await _apiService.usersApi.getMyPreferences();
|
|
||||||
if (user != null) {
|
|
||||||
await Store.put(
|
|
||||||
StoreKey.currentUser,
|
|
||||||
UserConverter.fromAdminDto(user, userPreferences),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,9 +31,7 @@ class CurrentUserProvider extends StateNotifier<UserDto?> {
|
|||||||
|
|
||||||
final currentUserProvider =
|
final currentUserProvider =
|
||||||
StateNotifierProvider<CurrentUserProvider, UserDto?>((ref) {
|
StateNotifierProvider<CurrentUserProvider, UserDto?>((ref) {
|
||||||
return CurrentUserProvider(
|
return CurrentUserProvider(ref.watch(userServiceProvider));
|
||||||
ref.watch(apiServiceProvider),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
class TimelineUserIdsProvider extends StateNotifier<List<int>> {
|
class TimelineUserIdsProvider extends StateNotifier<List<int>> {
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/asset.provider.dart';
|
import 'package:immich_mobile/providers/asset.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/providers/memory.provider.dart';
|
import 'package:immich_mobile/providers/memory.provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
|
|
||||||
@ -28,19 +25,7 @@ class TabNavigationObserver extends AutoRouterObserver {
|
|||||||
|
|
||||||
// Update user info
|
// Update user info
|
||||||
try {
|
try {
|
||||||
final userResponseDto =
|
ref.read(userServiceProvider).refreshMyUser();
|
||||||
await ref.read(apiServiceProvider).usersApi.getMyUser();
|
|
||||||
final userPreferences =
|
|
||||||
await ref.read(apiServiceProvider).usersApi.getMyPreferences();
|
|
||||||
|
|
||||||
if (userResponseDto == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Store.put(
|
|
||||||
StoreKey.currentUser,
|
|
||||||
UserConverter.fromAdminDto(userResponseDto, userPreferences),
|
|
||||||
);
|
|
||||||
ref.read(serverInfoProvider.notifier).getServerVersion();
|
ref.read(serverInfoProvider.notifier).getServerVersion();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("Error refreshing user info $e");
|
debugPrint("Error refreshing user info $e");
|
||||||
|
@ -6,12 +6,11 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.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/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/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/backup_album.entity.dart';
|
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.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/interfaces/album.interface.dart';
|
import 'package:immich_mobile/interfaces/album.interface.dart';
|
||||||
@ -21,6 +20,7 @@ import 'package:immich_mobile/interfaces/asset.interface.dart';
|
|||||||
import 'package:immich_mobile/interfaces/backup_album.interface.dart';
|
import 'package:immich_mobile/interfaces/backup_album.interface.dart';
|
||||||
import 'package:immich_mobile/models/albums/album_add_asset_response.model.dart';
|
import 'package:immich_mobile/models/albums/album_add_asset_response.model.dart';
|
||||||
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/album.repository.dart';
|
import 'package:immich_mobile/repositories/album.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/album_api.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/album_media.repository.dart';
|
||||||
@ -33,6 +33,7 @@ import 'package:logging/logging.dart';
|
|||||||
final albumServiceProvider = Provider(
|
final albumServiceProvider = Provider(
|
||||||
(ref) => AlbumService(
|
(ref) => AlbumService(
|
||||||
ref.watch(syncServiceProvider),
|
ref.watch(syncServiceProvider),
|
||||||
|
ref.watch(userServiceProvider),
|
||||||
ref.watch(entityServiceProvider),
|
ref.watch(entityServiceProvider),
|
||||||
ref.watch(albumRepositoryProvider),
|
ref.watch(albumRepositoryProvider),
|
||||||
ref.watch(assetRepositoryProvider),
|
ref.watch(assetRepositoryProvider),
|
||||||
@ -44,6 +45,7 @@ final albumServiceProvider = Provider(
|
|||||||
|
|
||||||
class AlbumService {
|
class AlbumService {
|
||||||
final SyncService _syncService;
|
final SyncService _syncService;
|
||||||
|
final UserService _userService;
|
||||||
final EntityService _entityService;
|
final EntityService _entityService;
|
||||||
final IAlbumRepository _albumRepository;
|
final IAlbumRepository _albumRepository;
|
||||||
final IAssetRepository _assetRepository;
|
final IAssetRepository _assetRepository;
|
||||||
@ -56,6 +58,7 @@ class AlbumService {
|
|||||||
|
|
||||||
AlbumService(
|
AlbumService(
|
||||||
this._syncService,
|
this._syncService,
|
||||||
|
this._userService,
|
||||||
this._entityService,
|
this._entityService,
|
||||||
this._albumRepository,
|
this._albumRepository,
|
||||||
this._assetRepository,
|
this._assetRepository,
|
||||||
@ -292,7 +295,7 @@ class AlbumService {
|
|||||||
|
|
||||||
Future<bool> deleteAlbum(Album album) async {
|
Future<bool> deleteAlbum(Album album) async {
|
||||||
try {
|
try {
|
||||||
final userId = Store.get(StoreKey.currentUser).id;
|
final userId = _userService.getMyUser().id;
|
||||||
if (album.owner.value?.isarId == userId) {
|
if (album.owner.value?.isarId == userId) {
|
||||||
await _albumApiRepository.delete(album.remoteId!);
|
await _albumApiRepository.delete(album.remoteId!);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@ class ApiService implements Authentication {
|
|||||||
late MemoriesApi memoriesApi;
|
late MemoriesApi memoriesApi;
|
||||||
|
|
||||||
ApiService() {
|
ApiService() {
|
||||||
|
// The below line ensures that the api clients are initialized when the service is instantiated
|
||||||
|
// This is required to avoid late initialization errors when the clients are access before the endpoint is resolved
|
||||||
|
setEndpoint('');
|
||||||
final endpoint = Store.tryGet(StoreKey.serverEndpoint);
|
final endpoint = Store.tryGet(StoreKey.serverEndpoint);
|
||||||
if (endpoint != null && endpoint.isNotEmpty) {
|
if (endpoint != null && endpoint.isNotEmpty) {
|
||||||
setEndpoint(endpoint);
|
setEndpoint(endpoint);
|
||||||
|
@ -6,9 +6,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.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.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/models/user.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.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/interfaces/asset.interface.dart';
|
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||||
@ -19,9 +18,7 @@ import 'package:immich_mobile/interfaces/etag.interface.dart';
|
|||||||
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart'
|
|
||||||
hide userServiceProvider;
|
|
||||||
import 'package:immich_mobile/repositories/asset.repository.dart';
|
import 'package:immich_mobile/repositories/asset.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/asset_api.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/asset_media.repository.dart';
|
||||||
@ -47,7 +44,7 @@ final assetServiceProvider = Provider(
|
|||||||
ref.watch(syncServiceProvider),
|
ref.watch(syncServiceProvider),
|
||||||
ref.watch(backupServiceProvider),
|
ref.watch(backupServiceProvider),
|
||||||
ref.watch(albumServiceProvider),
|
ref.watch(albumServiceProvider),
|
||||||
ref.watch(storeServiceProvider),
|
ref.watch(userServiceProvider),
|
||||||
ref.watch(assetMediaRepositoryProvider),
|
ref.watch(assetMediaRepositoryProvider),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -63,7 +60,7 @@ class AssetService {
|
|||||||
final SyncService _syncService;
|
final SyncService _syncService;
|
||||||
final BackupService _backupService;
|
final BackupService _backupService;
|
||||||
final AlbumService _albumService;
|
final AlbumService _albumService;
|
||||||
final StoreService _storeService;
|
final UserService _userService;
|
||||||
final IAssetMediaRepository _assetMediaRepository;
|
final IAssetMediaRepository _assetMediaRepository;
|
||||||
final log = Logger('AssetService');
|
final log = Logger('AssetService');
|
||||||
|
|
||||||
@ -78,7 +75,7 @@ class AssetService {
|
|||||||
this._syncService,
|
this._syncService,
|
||||||
this._backupService,
|
this._backupService,
|
||||||
this._albumService,
|
this._albumService,
|
||||||
this._storeService,
|
this._userService,
|
||||||
this._assetMediaRepository,
|
this._assetMediaRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -316,7 +313,7 @@ class AssetService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await refreshRemoteAssets();
|
await refreshRemoteAssets();
|
||||||
final owner = _storeService.get(StoreKey.currentUser);
|
final owner = _userService.getMyUser();
|
||||||
final remoteAssets = await _assetRepository.getAll(
|
final remoteAssets = await _assetRepository.getAll(
|
||||||
ownerId: owner.id,
|
ownerId: owner.id,
|
||||||
state: AssetState.merged,
|
state: AssetState.merged,
|
||||||
@ -522,12 +519,12 @@ class AssetService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Asset>> getRecentlyAddedAssets() {
|
Future<List<Asset>> getRecentlyAddedAssets() {
|
||||||
final me = _storeService.get(StoreKey.currentUser);
|
final me = _userService.getMyUser();
|
||||||
return _assetRepository.getRecentlyAddedAssets(me.id);
|
return _assetRepository.getRecentlyAddedAssets(me.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Asset>> getMotionAssets() {
|
Future<List<Asset>> getMotionAssets() {
|
||||||
final me = _storeService.get(StoreKey.currentUser);
|
final me = _userService.getMyUser();
|
||||||
return _assetRepository.getMotionAssets(me.id);
|
return _assetRepository.getMotionAssets(me.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,14 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.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/user.service.dart';
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
|
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
|
||||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||||
import 'package:immich_mobile/interfaces/file_media.interface.dart';
|
import 'package:immich_mobile/interfaces/file_media.interface.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/exif.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';
|
||||||
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
@ -22,11 +24,13 @@ import 'package:immich_mobile/utils/diff.dart';
|
|||||||
|
|
||||||
/// Finds duplicates originating from missing EXIF information
|
/// Finds duplicates originating from missing EXIF information
|
||||||
class BackupVerificationService {
|
class BackupVerificationService {
|
||||||
|
final UserService _userService;
|
||||||
final IFileMediaRepository _fileMediaRepository;
|
final IFileMediaRepository _fileMediaRepository;
|
||||||
final IAssetRepository _assetRepository;
|
final IAssetRepository _assetRepository;
|
||||||
final IExifInfoRepository _exifInfoRepository;
|
final IExifInfoRepository _exifInfoRepository;
|
||||||
|
|
||||||
BackupVerificationService(
|
const BackupVerificationService(
|
||||||
|
this._userService,
|
||||||
this._fileMediaRepository,
|
this._fileMediaRepository,
|
||||||
this._assetRepository,
|
this._assetRepository,
|
||||||
this._exifInfoRepository,
|
this._exifInfoRepository,
|
||||||
@ -34,7 +38,7 @@ class BackupVerificationService {
|
|||||||
|
|
||||||
/// Returns at most [limit] assets that were backed up without exif
|
/// Returns at most [limit] assets that were backed up without exif
|
||||||
Future<List<Asset>> findWronglyBackedUpAssets({int limit = 100}) async {
|
Future<List<Asset>> findWronglyBackedUpAssets({int limit = 100}) async {
|
||||||
final owner = Store.get(StoreKey.currentUser).id;
|
final owner = _userService.getMyUser().id;
|
||||||
final List<Asset> onlyLocal = await _assetRepository.getAll(
|
final List<Asset> onlyLocal = await _assetRepository.getAll(
|
||||||
ownerId: owner,
|
ownerId: owner,
|
||||||
state: AssetState.local,
|
state: AssetState.local,
|
||||||
@ -214,6 +218,7 @@ class BackupVerificationService {
|
|||||||
|
|
||||||
final backupVerificationServiceProvider = Provider(
|
final backupVerificationServiceProvider = Provider(
|
||||||
(ref) => BackupVerificationService(
|
(ref) => BackupVerificationService(
|
||||||
|
ref.watch(userServiceProvider),
|
||||||
ref.watch(fileMediaRepositoryProvider),
|
ref.watch(fileMediaRepositoryProvider),
|
||||||
ref.watch(assetRepositoryProvider),
|
ref.watch(assetRepositoryProvider),
|
||||||
ref.watch(exifRepositoryProvider),
|
ref.watch(exifRepositoryProvider),
|
||||||
|
@ -5,9 +5,8 @@ import 'package:hooks_riverpod/hooks_riverpod.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.interface.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
|
import 'package:immich_mobile/domain/interfaces/user_api.repository.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.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';
|
||||||
@ -20,7 +19,6 @@ import 'package:immich_mobile/interfaces/etag.interface.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/exif.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
|
|
||||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/album.repository.dart';
|
import 'package:immich_mobile/repositories/album.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/album_api.repository.dart';
|
import 'package:immich_mobile/repositories/album_api.repository.dart';
|
||||||
@ -47,7 +45,7 @@ final syncServiceProvider = Provider(
|
|||||||
ref.watch(exifRepositoryProvider),
|
ref.watch(exifRepositoryProvider),
|
||||||
ref.watch(partnerRepositoryProvider),
|
ref.watch(partnerRepositoryProvider),
|
||||||
ref.watch(userRepositoryProvider),
|
ref.watch(userRepositoryProvider),
|
||||||
ref.watch(storeServiceProvider),
|
ref.watch(userServiceProvider),
|
||||||
ref.watch(etagRepositoryProvider),
|
ref.watch(etagRepositoryProvider),
|
||||||
ref.watch(partnerApiRepositoryProvider),
|
ref.watch(partnerApiRepositoryProvider),
|
||||||
ref.watch(userApiRepositoryProvider),
|
ref.watch(userApiRepositoryProvider),
|
||||||
@ -63,8 +61,8 @@ class SyncService {
|
|||||||
final IAssetRepository _assetRepository;
|
final IAssetRepository _assetRepository;
|
||||||
final IExifInfoRepository _exifInfoRepository;
|
final IExifInfoRepository _exifInfoRepository;
|
||||||
final IUserRepository _userRepository;
|
final IUserRepository _userRepository;
|
||||||
|
final UserService _userService;
|
||||||
final IPartnerRepository _partnerRepository;
|
final IPartnerRepository _partnerRepository;
|
||||||
final StoreService _storeService;
|
|
||||||
final IETagRepository _eTagRepository;
|
final IETagRepository _eTagRepository;
|
||||||
final IPartnerApiRepository _partnerApiRepository;
|
final IPartnerApiRepository _partnerApiRepository;
|
||||||
final IUserApiRepository _userApiRepository;
|
final IUserApiRepository _userApiRepository;
|
||||||
@ -81,7 +79,7 @@ class SyncService {
|
|||||||
this._exifInfoRepository,
|
this._exifInfoRepository,
|
||||||
this._partnerRepository,
|
this._partnerRepository,
|
||||||
this._userRepository,
|
this._userRepository,
|
||||||
this._storeService,
|
this._userService,
|
||||||
this._eTagRepository,
|
this._eTagRepository,
|
||||||
this._partnerApiRepository,
|
this._partnerApiRepository,
|
||||||
this._userApiRepository,
|
this._userApiRepository,
|
||||||
@ -210,7 +208,7 @@ class SyncService {
|
|||||||
DateTime since,
|
DateTime since,
|
||||||
) getChangedAssets,
|
) getChangedAssets,
|
||||||
) async {
|
) async {
|
||||||
final currentUser = _storeService.get(StoreKey.currentUser);
|
final currentUser = _userService.getMyUser();
|
||||||
final DateTime? since =
|
final DateTime? since =
|
||||||
(await _eTagRepository.get(currentUser.id))?.time?.toUtc();
|
(await _eTagRepository.get(currentUser.id))?.time?.toUtc();
|
||||||
if (since == null) return null;
|
if (since == null) return null;
|
||||||
@ -261,7 +259,7 @@ class SyncService {
|
|||||||
|
|
||||||
Future<List<UserDto>> _getAllAccessibleUsers() async {
|
Future<List<UserDto>> _getAllAccessibleUsers() async {
|
||||||
final sharedWith = (await _partnerRepository.getSharedWith()).toSet();
|
final sharedWith = (await _partnerRepository.getSharedWith()).toSet();
|
||||||
sharedWith.add(_storeService.get(StoreKey.currentUser));
|
sharedWith.add(_userService.getMyUser());
|
||||||
return sharedWith.toList();
|
return sharedWith.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,7 +453,7 @@ class SyncService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (album.shared || dto.shared) {
|
if (album.shared || dto.shared) {
|
||||||
final userId = (_storeService.get(StoreKey.currentUser)).id;
|
final userId = (_userService.getMyUser()).id;
|
||||||
final foreign =
|
final foreign =
|
||||||
await _assetRepository.getByAlbum(album, notOwnedBy: [userId]);
|
await _assetRepository.getByAlbum(album, notOwnedBy: [userId]);
|
||||||
existing.addAll(foreign);
|
existing.addAll(foreign);
|
||||||
@ -591,7 +589,7 @@ class SyncService {
|
|||||||
// general case, e.g. some assets have been deleted or there are excluded albums on iOS
|
// general case, e.g. some assets have been deleted or there are excluded albums on iOS
|
||||||
final inDb = await _assetRepository.getByAlbum(
|
final inDb = await _assetRepository.getByAlbum(
|
||||||
dbAlbum,
|
dbAlbum,
|
||||||
ownerId: (_storeService.get(StoreKey.currentUser)).id,
|
ownerId: (_userService.getMyUser()).id,
|
||||||
sortBy: AssetSort.checksum,
|
sortBy: AssetSort.checksum,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/services/user.service.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.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/interfaces/timeline.interface.dart';
|
import 'package:immich_mobile/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/providers/app_settings.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/timeline.repository.dart';
|
import 'package:immich_mobile/repositories/timeline.repository.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
||||||
@ -14,28 +13,28 @@ final timelineServiceProvider = Provider<TimelineService>((ref) {
|
|||||||
return TimelineService(
|
return TimelineService(
|
||||||
ref.watch(timelineRepositoryProvider),
|
ref.watch(timelineRepositoryProvider),
|
||||||
ref.watch(appSettingsServiceProvider),
|
ref.watch(appSettingsServiceProvider),
|
||||||
ref.watch(storeServiceProvider),
|
ref.watch(userServiceProvider),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
class TimelineService {
|
class TimelineService {
|
||||||
final ITimelineRepository _timelineRepository;
|
final ITimelineRepository _timelineRepository;
|
||||||
final AppSettingsService _appSettingsService;
|
final AppSettingsService _appSettingsService;
|
||||||
final StoreService _storeService;
|
final UserService _userService;
|
||||||
|
|
||||||
const TimelineService(
|
const TimelineService(
|
||||||
this._timelineRepository,
|
this._timelineRepository,
|
||||||
this._appSettingsService,
|
this._appSettingsService,
|
||||||
this._storeService,
|
this._userService,
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<List<int>> getTimelineUserIds() async {
|
Future<List<int>> getTimelineUserIds() async {
|
||||||
final me = _storeService.get(StoreKey.currentUser);
|
final me = _userService.getMyUser();
|
||||||
return _timelineRepository.getTimelineUserIds(me.id);
|
return _timelineRepository.getTimelineUserIds(me.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<int>> watchTimelineUserIds() async* {
|
Stream<List<int>> watchTimelineUserIds() async* {
|
||||||
final me = _storeService.get(StoreKey.currentUser);
|
final me = _userService.getMyUser();
|
||||||
yield* _timelineRepository.watchTimelineUsers(me.id);
|
yield* _timelineRepository.watchTimelineUsers(me.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,13 +50,13 @@ class TimelineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream<RenderList> watchArchiveTimeline() async* {
|
Stream<RenderList> watchArchiveTimeline() async* {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
yield* _timelineRepository.watchArchiveTimeline(user.id);
|
yield* _timelineRepository.watchArchiveTimeline(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<RenderList> watchFavoriteTimeline() async* {
|
Stream<RenderList> watchFavoriteTimeline() async* {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
yield* _timelineRepository.watchFavoriteTimeline(user.id);
|
yield* _timelineRepository.watchFavoriteTimeline(user.id);
|
||||||
}
|
}
|
||||||
@ -70,7 +69,7 @@ class TimelineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream<RenderList> watchTrashTimeline() async* {
|
Stream<RenderList> watchTrashTimeline() async* {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
yield* _timelineRepository.watchTrashTimeline(user.id);
|
yield* _timelineRepository.watchTrashTimeline(user.id);
|
||||||
}
|
}
|
||||||
@ -97,7 +96,7 @@ class TimelineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream<RenderList> watchAssetSelectionTimeline() async* {
|
Stream<RenderList> watchAssetSelectionTimeline() async* {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
yield* _timelineRepository.watchAssetSelectionTimeline(user.id);
|
yield* _timelineRepository.watchAssetSelectionTimeline(user.id);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/services/user.service.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
import 'package:immich_mobile/interfaces/asset.interface.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.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.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
@ -13,19 +12,19 @@ final trashServiceProvider = Provider<TrashService>((ref) {
|
|||||||
return TrashService(
|
return TrashService(
|
||||||
ref.watch(apiServiceProvider),
|
ref.watch(apiServiceProvider),
|
||||||
ref.watch(assetRepositoryProvider),
|
ref.watch(assetRepositoryProvider),
|
||||||
ref.watch(storeServiceProvider),
|
ref.watch(userServiceProvider),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
class TrashService {
|
class TrashService {
|
||||||
final ApiService _apiService;
|
final ApiService _apiService;
|
||||||
final IAssetRepository _assetRepository;
|
final IAssetRepository _assetRepository;
|
||||||
final StoreService _storeService;
|
final UserService _userService;
|
||||||
|
|
||||||
TrashService(
|
const TrashService(
|
||||||
this._apiService,
|
this._apiService,
|
||||||
this._assetRepository,
|
this._assetRepository,
|
||||||
this._storeService,
|
this._userService,
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> restoreAssets(Iterable<Asset> assetList) async {
|
Future<void> restoreAssets(Iterable<Asset> assetList) async {
|
||||||
@ -43,7 +42,7 @@ class TrashService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> emptyTrash() async {
|
Future<void> emptyTrash() async {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
await _apiService.trashApi.emptyTrash();
|
await _apiService.trashApi.emptyTrash();
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ class TrashService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> restoreTrash() async {
|
Future<void> restoreTrash() async {
|
||||||
final user = _storeService.get(StoreKey.currentUser);
|
final user = _userService.getMyUser();
|
||||||
|
|
||||||
await _apiService.trashApi.restoreTrash();
|
await _apiService.trashApi.restoreTrash();
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/entities/album.entity.dart';
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
|
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
|
||||||
|
|
||||||
class AlbumThumbnailCard extends StatelessWidget {
|
class AlbumThumbnailCard extends ConsumerWidget {
|
||||||
final Function()? onTap;
|
final Function()? onTap;
|
||||||
|
|
||||||
/// Whether or not to show the owner of the album (or "Owned")
|
/// Whether or not to show the owner of the album (or "Owned")
|
||||||
@ -26,7 +26,7 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
final Album album;
|
final Album album;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
var cardSize = constraints.maxWidth;
|
var cardSize = constraints.maxWidth;
|
||||||
@ -58,7 +58,7 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
// Add the owner name to the subtitle
|
// Add the owner name to the subtitle
|
||||||
String? owner;
|
String? owner;
|
||||||
if (showOwner) {
|
if (showOwner) {
|
||||||
if (album.ownerId == Store.get(StoreKey.currentUser).uid) {
|
if (album.ownerId == ref.read(currentUserProvider)?.uid) {
|
||||||
owner = 'album_thumbnail_owned'.tr();
|
owner = 'album_thumbnail_owned'.tr();
|
||||||
} else if (album.ownerName != null) {
|
} else if (album.ownerName != null) {
|
||||||
owner = 'album_thumbnail_shared_by'.tr(args: [album.ownerName!]);
|
owner = 'album_thumbnail_shared_by'.tr(args: [album.ownerName!]);
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
@ -21,7 +19,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
|
|||||||
final authState = ref.watch(authProvider);
|
final authState = ref.watch(authProvider);
|
||||||
final uploadProfileImageStatus =
|
final uploadProfileImageStatus =
|
||||||
ref.watch(uploadProfileImageProvider).status;
|
ref.watch(uploadProfileImageProvider).status;
|
||||||
final user = Store.tryGet(StoreKey.currentUser);
|
final user = ref.watch(currentUserProvider);
|
||||||
|
|
||||||
buildUserProfileImage() {
|
buildUserProfileImage() {
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
@ -67,9 +65,6 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
|
|||||||
profileImagePath,
|
profileImagePath,
|
||||||
);
|
);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
final updatedUser =
|
|
||||||
user.copyWith(profileImagePath: profileImagePath);
|
|
||||||
await Store.put(StoreKey.currentUser, updatedUser);
|
|
||||||
ref.read(currentUserProvider.notifier).refresh();
|
ref.read(currentUserProvider.notifier).refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,13 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/immich_logo_provider.dart';
|
import 'package:immich_mobile/providers/immich_logo_provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/widgets/common/app_bar_dialog/app_bar_dialog.dart';
|
import 'package:immich_mobile/widgets/common/app_bar_dialog/app_bar_dialog.dart';
|
||||||
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
|
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
|
||||||
@ -30,7 +29,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
|
|||||||
backupState.backgroundBackup || backupState.autoBackup;
|
backupState.backgroundBackup || backupState.autoBackup;
|
||||||
final ServerInfo serverInfoState = ref.watch(serverInfoProvider);
|
final ServerInfo serverInfoState = ref.watch(serverInfoProvider);
|
||||||
final immichLogo = ref.watch(immichLogoProvider);
|
final immichLogo = ref.watch(immichLogoProvider);
|
||||||
final user = Store.tryGet(StoreKey.currentUser);
|
final user = ref.watch(currentUserProvider);
|
||||||
final isDarkTheme = context.isDarkTheme;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
const widgetSize = 30.0;
|
const widgetSize = 30.0;
|
||||||
|
|
||||||
|
@ -27,12 +27,16 @@ void main() {
|
|||||||
userApiRepository: mockUserApiRepo,
|
userApiRepository: mockUserApiRepo,
|
||||||
storeService: mockStoreService,
|
storeService: mockStoreService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
registerFallbackValue(UserStub.admin);
|
||||||
|
when(() => mockStoreService.get(StoreKey.currentUser))
|
||||||
|
.thenReturn(UserStub.admin);
|
||||||
|
when(() => mockStoreService.tryGet(StoreKey.currentUser))
|
||||||
|
.thenReturn(UserStub.admin);
|
||||||
});
|
});
|
||||||
|
|
||||||
group('getMyUser', () {
|
group('getMyUser', () {
|
||||||
test('should return user from store', () {
|
test('should return user from store', () {
|
||||||
when(() => mockStoreService.get(StoreKey.currentUser))
|
|
||||||
.thenReturn(UserStub.admin);
|
|
||||||
final result = sut.getMyUser();
|
final result = sut.getMyUser();
|
||||||
expect(result, UserStub.admin);
|
expect(result, UserStub.admin);
|
||||||
});
|
});
|
||||||
@ -47,8 +51,6 @@ void main() {
|
|||||||
|
|
||||||
group('tryGetMyUser', () {
|
group('tryGetMyUser', () {
|
||||||
test('should return user from store', () {
|
test('should return user from store', () {
|
||||||
when(() => mockStoreService.tryGet(StoreKey.currentUser))
|
|
||||||
.thenReturn(UserStub.admin);
|
|
||||||
final result = sut.tryGetMyUser();
|
final result = sut.tryGetMyUser();
|
||||||
expect(result, UserStub.admin);
|
expect(result, UserStub.admin);
|
||||||
});
|
});
|
||||||
@ -107,26 +109,48 @@ void main() {
|
|||||||
|
|
||||||
group('createProfileImage', () {
|
group('createProfileImage', () {
|
||||||
test('should return profile image path', () async {
|
test('should return profile image path', () async {
|
||||||
|
const profileImagePath = 'profile.jpg';
|
||||||
|
final updatedUser =
|
||||||
|
UserStub.admin.copyWith(profileImagePath: profileImagePath);
|
||||||
|
|
||||||
when(
|
when(
|
||||||
() => mockUserApiRepo.createProfileImage(
|
() => mockUserApiRepo.createProfileImage(
|
||||||
name: 'profile.jpg',
|
name: profileImagePath,
|
||||||
data: Uint8List(0),
|
data: Uint8List(0),
|
||||||
),
|
),
|
||||||
).thenAnswer((_) async => 'profile.jpg');
|
).thenAnswer((_) async => profileImagePath);
|
||||||
|
when(() => mockStoreService.put(StoreKey.currentUser, updatedUser))
|
||||||
|
.thenAnswer((_) async => true);
|
||||||
|
when(() => mockUserRepo.update(updatedUser))
|
||||||
|
.thenAnswer((_) async => UserStub.admin);
|
||||||
|
|
||||||
final result = await sut.createProfileImage('profile.jpg', Uint8List(0));
|
final result =
|
||||||
expect(result, 'profile.jpg');
|
await sut.createProfileImage(profileImagePath, Uint8List(0));
|
||||||
|
|
||||||
|
verify(() => mockStoreService.put(StoreKey.currentUser, updatedUser))
|
||||||
|
.called(1);
|
||||||
|
verify(() => mockUserRepo.update(updatedUser)).called(1);
|
||||||
|
expect(result, profileImagePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return null if profile image creation fails', () async {
|
test('should return null if profile image creation fails', () async {
|
||||||
|
const profileImagePath = 'profile.jpg';
|
||||||
|
final updatedUser =
|
||||||
|
UserStub.admin.copyWith(profileImagePath: profileImagePath);
|
||||||
|
|
||||||
when(
|
when(
|
||||||
() => mockUserApiRepo.createProfileImage(
|
() => mockUserApiRepo.createProfileImage(
|
||||||
name: 'profile.jpg',
|
name: profileImagePath,
|
||||||
data: Uint8List(0),
|
data: Uint8List(0),
|
||||||
),
|
),
|
||||||
).thenThrow(Exception('Failed to create profile image'));
|
).thenThrow(Exception('Failed to create profile image'));
|
||||||
|
|
||||||
final result = await sut.createProfileImage('profile.jpg', Uint8List(0));
|
final result =
|
||||||
|
await sut.createProfileImage(profileImagePath, Uint8List(0));
|
||||||
|
verifyNever(
|
||||||
|
() => mockStoreService.put(StoreKey.currentUser, updatedUser),
|
||||||
|
);
|
||||||
|
verifyNever(() => mockUserRepo.update(updatedUser));
|
||||||
expect(result, isNull);
|
expect(result, isNull);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,6 +15,7 @@ import 'package:immich_mobile/interfaces/partner_api.interface.dart';
|
|||||||
import 'package:immich_mobile/services/sync.service.dart';
|
import 'package:immich_mobile/services/sync.service.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
|
||||||
|
import '../../domain/service.mock.dart';
|
||||||
import '../../infrastructure/repository.mock.dart';
|
import '../../infrastructure/repository.mock.dart';
|
||||||
import '../../repository.mocks.dart';
|
import '../../repository.mocks.dart';
|
||||||
import '../../service.mocks.dart';
|
import '../../service.mocks.dart';
|
||||||
@ -62,6 +63,7 @@ void main() {
|
|||||||
MockPartnerApiRepository();
|
MockPartnerApiRepository();
|
||||||
final MockUserApiRepository userApiRepository = MockUserApiRepository();
|
final MockUserApiRepository userApiRepository = MockUserApiRepository();
|
||||||
final MockPartnerRepository partnerRepository = MockPartnerRepository();
|
final MockPartnerRepository partnerRepository = MockPartnerRepository();
|
||||||
|
final MockUserService userService = MockUserService();
|
||||||
|
|
||||||
final owner = UserDto(
|
final owner = UserDto(
|
||||||
uid: "1",
|
uid: "1",
|
||||||
@ -101,11 +103,12 @@ void main() {
|
|||||||
exifInfoRepository,
|
exifInfoRepository,
|
||||||
partnerRepository,
|
partnerRepository,
|
||||||
userRepository,
|
userRepository,
|
||||||
StoreService.I,
|
userService,
|
||||||
eTagRepository,
|
eTagRepository,
|
||||||
partnerApiRepository,
|
partnerApiRepository,
|
||||||
userApiRepository,
|
userApiRepository,
|
||||||
);
|
);
|
||||||
|
when(() => userService.getMyUser()).thenReturn(owner);
|
||||||
when(() => eTagRepository.get(owner.id))
|
when(() => eTagRepository.get(owner.id))
|
||||||
.thenAnswer((_) async => ETag(id: owner.uid, time: DateTime.now()));
|
.thenAnswer((_) async => ETag(id: owner.uid, time: DateTime.now()));
|
||||||
when(() => eTagRepository.deleteByIds(["1"])).thenAnswer((_) async {});
|
when(() => eTagRepository.deleteByIds(["1"])).thenAnswer((_) async {});
|
||||||
|
@ -31,6 +31,8 @@ void main() {
|
|||||||
albumMediaRepository = MockAlbumMediaRepository();
|
albumMediaRepository = MockAlbumMediaRepository();
|
||||||
albumApiRepository = MockAlbumApiRepository();
|
albumApiRepository = MockAlbumApiRepository();
|
||||||
|
|
||||||
|
when(() => userService.getMyUser()).thenReturn(UserStub.user1);
|
||||||
|
|
||||||
when(() => albumRepository.transaction<void>(any())).thenAnswer(
|
when(() => albumRepository.transaction<void>(any())).thenAnswer(
|
||||||
(call) => (call.positionalArguments.first as Function).call(),
|
(call) => (call.positionalArguments.first as Function).call(),
|
||||||
);
|
);
|
||||||
@ -40,6 +42,7 @@ void main() {
|
|||||||
|
|
||||||
sut = AlbumService(
|
sut = AlbumService(
|
||||||
syncService,
|
syncService,
|
||||||
|
userService,
|
||||||
entityService,
|
entityService,
|
||||||
albumRepository,
|
albumRepository,
|
||||||
assetRepository,
|
assetRepository,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user