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:
shenlong 2025-03-12 19:26:56 +05:30 committed by GitHub
parent a75718ce99
commit d1c8fe5303
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 1039 additions and 947 deletions

View file

@ -2,11 +2,11 @@ import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/user.entity.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/models/albums/album_search.model.dart';
import 'package:immich_mobile/services/album.service.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/album.entity.dart';
final isRefreshingRemoteAlbumProvider = StateProvider<bool>((ref) => false);
@ -88,7 +88,7 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
await albumService.addUsers(album, userIds);
}
Future<bool> removeUser(Album album, User user) async {
Future<bool> removeUser(Album album, UserDto user) async {
final isRemoved = await albumService.removeUser(album, user);
if (isRemoved && album.sharedUsers.isEmpty) {

View file

@ -1,9 +1,14 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/services/user.service.dart';
final otherUsersProvider = FutureProvider.autoDispose<List<User>>((ref) {
final otherUsersProvider =
FutureProvider.autoDispose<List<UserDto>>((ref) async {
UserService userService = ref.watch(userServiceProvider);
final currentUser = ref.watch(currentUserProvider);
return userService.getUsers();
final allUsers = await userService.getAll();
allUsers.removeWhere((u) => currentUser?.id == u.id);
return allUsers;
});

View file

@ -2,8 +2,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_udid/flutter_udid.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/entities/store.entity.dart';
import 'package:immich_mobile/entities/user.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/login_response.model.dart';
import 'package:immich_mobile/providers/api.provider.dart';
@ -105,7 +106,7 @@ class AuthNotifier extends StateNotifier<AuthState> {
String deviceId =
Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid;
User? user = Store.tryGet(StoreKey.currentUser);
UserDto? user = Store.tryGet(StoreKey.currentUser);
UserAdminResponseDto? userResponse;
UserPreferencesResponseDto? userPreferences;
@ -141,18 +142,18 @@ 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) {
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,
User.fromUserDto(userResponse, userPreferences),
UserConverter.fromAdminDto(userResponse, userPreferences),
);
await Store.put(StoreKey.accessToken, accessToken);
user = User.fromUserDto(userResponse, userPreferences);
} else {
_log.severe("Unable to get user information from the server.");
user = UserConverter.fromAdminDto(userResponse, userPreferences);
}
// If the user is null, the login was not successful
@ -163,7 +164,7 @@ class AuthNotifier extends StateNotifier<AuthState> {
state = state.copyWith(
isAuthenticated: true,
userId: user.id,
userId: user.uid,
userEmail: user.email,
name: user.name,
profileImagePath: user.profileImagePath,

View file

@ -1,11 +1,15 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'store.provider.g.dart';
@riverpod
@Riverpod(keepAlive: true)
IStoreRepository storeRepository(Ref ref) =>
IsarStoreRepository(ref.watch(isarProvider));
@Riverpod(keepAlive: true)
StoreService storeService(Ref _) => StoreService.I;

View file

@ -6,11 +6,11 @@ part of 'store.provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$storeRepositoryHash() => r'9f378b96e552151fa14a8c8ce2c30a5f38f436ed';
String _$storeRepositoryHash() => r'99d24875d30c5e86b1c6caa352a0026167114e62';
/// See also [storeRepository].
@ProviderFor(storeRepository)
final storeRepositoryProvider = AutoDisposeProvider<IStoreRepository>.internal(
final storeRepositoryProvider = Provider<IStoreRepository>.internal(
storeRepository,
name: r'storeRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@ -22,6 +22,22 @@ final storeRepositoryProvider = AutoDisposeProvider<IStoreRepository>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef StoreRepositoryRef = AutoDisposeProviderRef<IStoreRepository>;
typedef StoreRepositoryRef = ProviderRef<IStoreRepository>;
String _$storeServiceHash() => r'250e10497c42df360e9e1f9a618d0b19c1b5b0a0';
/// See also [storeService].
@ProviderFor(storeService)
final storeServiceProvider = Provider<StoreService>.internal(
storeService,
name: r'storeServiceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$storeServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef StoreServiceRef = ProviderRef<StoreService>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -0,0 +1,11 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user.provider.g.dart';
@Riverpod(keepAlive: true)
IUserRepository userRepository(Ref ref) =>
IsarUserRepository(ref.watch(isarProvider));

View file

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$userRepositoryHash() => r'1a2ac726bcc44397dcaecf449084fefd336696d4';
/// See also [userRepository].
@ProviderFor(userRepository)
final userRepositoryProvider = Provider<IUserRepository>.internal(
userRepository,
name: r'userRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$userRepositoryHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef UserRepositoryRef = ProviderRef<IUserRepository>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -2,16 +2,16 @@ import 'dart:async';
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/providers/album/suggested_shared_users.provider.dart';
import 'package:immich_mobile/services/partner.service.dart';
import 'package:immich_mobile/entities/user.entity.dart';
class PartnerSharedWithNotifier extends StateNotifier<List<User>> {
class PartnerSharedWithNotifier extends StateNotifier<List<UserDto>> {
final PartnerService _partnerService;
late final StreamSubscription<List<User>> streamSub;
late final StreamSubscription<List<UserDto>> streamSub;
PartnerSharedWithNotifier(this._partnerService) : super([]) {
Function eq = const ListEquality<User>().equals;
Function eq = const ListEquality<UserDto>().equals;
_partnerService.getSharedWith().then((partners) {
if (!eq(state, partners)) {
state = partners;
@ -25,7 +25,7 @@ class PartnerSharedWithNotifier extends StateNotifier<List<User>> {
});
}
Future<bool> updatePartner(User partner, {required bool inTimeline}) {
Future<bool> updatePartner(UserDto partner, {required bool inTimeline}) {
return _partnerService.updatePartner(partner, inTimeline: inTimeline);
}
@ -39,18 +39,18 @@ class PartnerSharedWithNotifier extends StateNotifier<List<User>> {
}
final partnerSharedWithProvider =
StateNotifierProvider<PartnerSharedWithNotifier, List<User>>((ref) {
StateNotifierProvider<PartnerSharedWithNotifier, List<UserDto>>((ref) {
return PartnerSharedWithNotifier(
ref.watch(partnerServiceProvider),
);
});
class PartnerSharedByNotifier extends StateNotifier<List<User>> {
class PartnerSharedByNotifier extends StateNotifier<List<UserDto>> {
final PartnerService _partnerService;
late final StreamSubscription<List<User>> streamSub;
late final StreamSubscription<List<UserDto>> streamSub;
PartnerSharedByNotifier(this._partnerService) : super([]) {
Function eq = const ListEquality<User>().equals;
Function eq = const ListEquality<UserDto>().equals;
_partnerService.getSharedBy().then((partners) {
if (!eq(state, partners)) {
state = partners;
@ -74,15 +74,15 @@ class PartnerSharedByNotifier extends StateNotifier<List<User>> {
}
final partnerSharedByProvider =
StateNotifierProvider<PartnerSharedByNotifier, List<User>>((ref) {
StateNotifierProvider<PartnerSharedByNotifier, List<UserDto>>((ref) {
return PartnerSharedByNotifier(ref.watch(partnerServiceProvider));
});
final partnerAvailableProvider =
FutureProvider.autoDispose<List<User>>((ref) async {
FutureProvider.autoDispose<List<UserDto>>((ref) async {
final otherUsers = await ref.watch(otherUsersProvider.future);
final currentPartners = ref.watch(partnerSharedByProvider);
final available = Set<User>.of(otherUsers);
final available = Set<UserDto>.of(otherUsers);
available.removeAll(currentPartners);
return available.toList();
});

View file

@ -2,13 +2,14 @@ import 'dart:async';
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/entities/store.entity.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/user.converter.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';
class CurrentUserProvider extends StateNotifier<User?> {
class CurrentUserProvider extends StateNotifier<UserDto?> {
CurrentUserProvider(this._apiService) : super(null) {
state = Store.tryGet(StoreKey.currentUser);
streamSub =
@ -16,7 +17,7 @@ class CurrentUserProvider extends StateNotifier<User?> {
}
final ApiService _apiService;
late final StreamSubscription<User?> streamSub;
late final StreamSubscription<UserDto?> streamSub;
refresh() async {
try {
@ -25,7 +26,7 @@ class CurrentUserProvider extends StateNotifier<User?> {
if (user != null) {
await Store.put(
StoreKey.currentUser,
User.fromUserDto(user, userPreferences),
UserConverter.fromAdminDto(user, userPreferences),
);
}
} catch (_) {}
@ -39,7 +40,7 @@ class CurrentUserProvider extends StateNotifier<User?> {
}
final currentUserProvider =
StateNotifierProvider<CurrentUserProvider, User?>((ref) {
StateNotifierProvider<CurrentUserProvider, UserDto?>((ref) {
return CurrentUserProvider(
ref.watch(apiServiceProvider),
);