mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
refactor(mobile): services and providers (#9232)
* refactor(mobile): services and provider * providers
This commit is contained in:
parent
ec4eb7cd19
commit
c1253663b7
242 changed files with 497 additions and 503 deletions
243
mobile/lib/providers/authentication.provider.dart
Normal file
243
mobile/lib/providers/authentication.provider.dart
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_udid/flutter_udid.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/shared_album.provider.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/models/authentication/authentication_state.model.dart';
|
||||
import 'package:immich_mobile/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/utils/db.dart';
|
||||
import 'package:immich_mobile/utils/hash.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
||||
AuthenticationNotifier(
|
||||
this._apiService,
|
||||
this._db,
|
||||
this._ref,
|
||||
) : super(
|
||||
AuthenticationState(
|
||||
deviceId: "",
|
||||
userId: "",
|
||||
userEmail: "",
|
||||
name: '',
|
||||
profileImagePath: '',
|
||||
isAdmin: false,
|
||||
shouldChangePassword: false,
|
||||
isAuthenticated: false,
|
||||
),
|
||||
);
|
||||
|
||||
final ApiService _apiService;
|
||||
final Isar _db;
|
||||
final StateNotifierProviderRef<AuthenticationNotifier, AuthenticationState>
|
||||
_ref;
|
||||
final _log = Logger("AuthenticationNotifier");
|
||||
|
||||
Future<bool> login(
|
||||
String email,
|
||||
String password,
|
||||
String serverUrl,
|
||||
) async {
|
||||
try {
|
||||
// Resolve API server endpoint from user provided serverUrl
|
||||
await _apiService.resolveAndSetEndpoint(serverUrl);
|
||||
await _apiService.serverInfoApi.pingServer();
|
||||
} catch (e) {
|
||||
debugPrint('Invalid Server Endpoint Url $e');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sign-in request
|
||||
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isIOS) {
|
||||
var iosInfo = await deviceInfoPlugin.iosInfo;
|
||||
_apiService.authenticationApi.apiClient
|
||||
.addDefaultHeader('deviceModel', iosInfo.utsname.machine);
|
||||
_apiService.authenticationApi.apiClient
|
||||
.addDefaultHeader('deviceType', 'iOS');
|
||||
} else {
|
||||
var androidInfo = await deviceInfoPlugin.androidInfo;
|
||||
_apiService.authenticationApi.apiClient
|
||||
.addDefaultHeader('deviceModel', androidInfo.model);
|
||||
_apiService.authenticationApi.apiClient
|
||||
.addDefaultHeader('deviceType', 'Android');
|
||||
}
|
||||
|
||||
try {
|
||||
var loginResponse = await _apiService.authenticationApi.login(
|
||||
LoginCredentialDto(
|
||||
email: email,
|
||||
password: password,
|
||||
),
|
||||
);
|
||||
|
||||
if (loginResponse == null) {
|
||||
debugPrint('Login Response is null');
|
||||
return false;
|
||||
}
|
||||
|
||||
return setSuccessLoginInfo(
|
||||
accessToken: loginResponse.accessToken,
|
||||
serverUrl: serverUrl,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint("Error logging in $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
var log = Logger('AuthenticationNotifier');
|
||||
try {
|
||||
String? userEmail = Store.tryGet(StoreKey.currentUser)?.email;
|
||||
|
||||
_apiService.authenticationApi
|
||||
.logout()
|
||||
.then((_) => log.info("Logout was successful for $userEmail"))
|
||||
.onError(
|
||||
(error, stackTrace) =>
|
||||
log.severe("Logout failed for $userEmail", error, stackTrace),
|
||||
);
|
||||
|
||||
await Future.wait([
|
||||
clearAssetsAndAlbums(_db),
|
||||
Store.delete(StoreKey.currentUser),
|
||||
Store.delete(StoreKey.accessToken),
|
||||
]);
|
||||
_ref.invalidate(albumProvider);
|
||||
_ref.invalidate(sharedAlbumProvider);
|
||||
|
||||
state = state.copyWith(
|
||||
deviceId: "",
|
||||
userId: "",
|
||||
userEmail: "",
|
||||
name: '',
|
||||
profileImagePath: '',
|
||||
isAdmin: false,
|
||||
shouldChangePassword: false,
|
||||
isAuthenticated: false,
|
||||
);
|
||||
} catch (e, stack) {
|
||||
log.severe('Logout failed', e, stack);
|
||||
}
|
||||
}
|
||||
|
||||
updateUserProfileImagePath(String path) {
|
||||
state = state.copyWith(profileImagePath: path);
|
||||
}
|
||||
|
||||
Future<bool> changePassword(String newPassword) async {
|
||||
try {
|
||||
await _apiService.userApi.updateUser(
|
||||
UpdateUserDto(
|
||||
id: state.userId,
|
||||
password: newPassword,
|
||||
shouldChangePassword: false,
|
||||
),
|
||||
);
|
||||
|
||||
state = state.copyWith(shouldChangePassword: false);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint("Error changing password $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> setSuccessLoginInfo({
|
||||
required String accessToken,
|
||||
required String serverUrl,
|
||||
bool offlineLogin = false,
|
||||
}) async {
|
||||
_apiService.setAccessToken(accessToken);
|
||||
|
||||
// Get the deviceid from the store if it exists, otherwise generate a new one
|
||||
String deviceId =
|
||||
Store.tryGet(StoreKey.deviceId) ?? await FlutterUdid.consistentUdid;
|
||||
|
||||
bool shouldChangePassword = false;
|
||||
User? user;
|
||||
|
||||
bool retResult = false;
|
||||
User? offlineUser = Store.tryGet(StoreKey.currentUser);
|
||||
|
||||
// If the user is offline and there is a user saved on the device,
|
||||
// if not try an online login
|
||||
if (offlineLogin && offlineUser != null) {
|
||||
user = offlineUser;
|
||||
retResult = false;
|
||||
} else {
|
||||
UserResponseDto? userResponseDto;
|
||||
try {
|
||||
userResponseDto = await _apiService.userApi.getMyUserInfo();
|
||||
} on ApiException catch (error, stackTrace) {
|
||||
_log.severe(
|
||||
"Error getting user information from the server [API EXCEPTION]",
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
if (error.innerException is SocketException) {
|
||||
state = state.copyWith(isAuthenticated: true);
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
_log.severe(
|
||||
"Error getting user information from the server [CATCH ALL]",
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
}
|
||||
|
||||
if (userResponseDto != null) {
|
||||
Store.put(StoreKey.deviceId, deviceId);
|
||||
Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
|
||||
Store.put(
|
||||
StoreKey.currentUser,
|
||||
User.fromUserDto(userResponseDto),
|
||||
);
|
||||
Store.put(StoreKey.serverUrl, serverUrl);
|
||||
Store.put(StoreKey.accessToken, accessToken);
|
||||
|
||||
shouldChangePassword = userResponseDto.shouldChangePassword;
|
||||
user = User.fromUserDto(userResponseDto);
|
||||
|
||||
retResult = true;
|
||||
} else {
|
||||
_log.severe("Unable to get user information from the server.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
isAuthenticated: true,
|
||||
userId: user.id,
|
||||
userEmail: user.email,
|
||||
name: user.name,
|
||||
profileImagePath: user.profileImagePath,
|
||||
isAdmin: user.isAdmin,
|
||||
shouldChangePassword: shouldChangePassword,
|
||||
deviceId: deviceId,
|
||||
);
|
||||
|
||||
return retResult;
|
||||
}
|
||||
}
|
||||
|
||||
final authenticationProvider =
|
||||
StateNotifierProvider<AuthenticationNotifier, AuthenticationState>((ref) {
|
||||
return AuthenticationNotifier(
|
||||
ref.watch(apiServiceProvider),
|
||||
ref.watch(dbProvider),
|
||||
ref,
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue