mirror of
https://github.com/immich-app/immich.git
synced 2025-04-23 13:09:00 +02:00
fix(mobile): ios random logout (#8997)
* fix(mobile): random logout * move logout mechanism to the end * More logs * wording * more logs * fixed * Better check
This commit is contained in:
parent
70c78a09a4
commit
48b0b7e8bd
@ -155,7 +155,7 @@ SPEC CHECKSUMS:
|
|||||||
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
|
||||||
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04
|
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04
|
||||||
flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d
|
flutter_web_auth: c25208760459cec375a3c39f6a8759165ca0fa4d
|
||||||
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
|
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
|
geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
|
||||||
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
||||||
@ -180,4 +180,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
|
PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d
|
||||||
|
|
||||||
COCOAPODS: 1.12.1
|
COCOAPODS: 1.15.2
|
||||||
|
@ -181,10 +181,21 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
UserResponseDto? userResponseDto;
|
UserResponseDto? userResponseDto;
|
||||||
try {
|
try {
|
||||||
userResponseDto = await _apiService.userApi.getMyUserInfo();
|
userResponseDto = await _apiService.userApi.getMyUserInfo();
|
||||||
} on ApiException catch (e) {
|
} on ApiException catch (error, stackTrace) {
|
||||||
if (e.innerException is SocketException) {
|
_log.severe(
|
||||||
|
"Error getting user information from the server [API EXCEPTION]",
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
);
|
||||||
|
if (error.innerException is SocketException) {
|
||||||
state = state.copyWith(isAuthenticated: true);
|
state = state.copyWith(isAuthenticated: true);
|
||||||
}
|
}
|
||||||
|
} catch (error, stackTrace) {
|
||||||
|
_log.severe(
|
||||||
|
"Error getting user information from the server [CATCH ALL]",
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userResponseDto != null) {
|
if (userResponseDto != null) {
|
||||||
|
@ -3,6 +3,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
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:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/oauth.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/oauth.provider.dart';
|
||||||
@ -86,6 +87,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: e.message ?? 'login_form_api_exception'.tr(),
|
msg: e.message ?? 'login_form_api_exception'.tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
isOauthEnable.value = false;
|
isOauthEnable.value = false;
|
||||||
isPasswordLoginEnable.value = true;
|
isPasswordLoginEnable.value = true;
|
||||||
@ -96,6 +98,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: 'login_form_handshake_exception'.tr(),
|
msg: 'login_form_handshake_exception'.tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
isOauthEnable.value = false;
|
isOauthEnable.value = false;
|
||||||
isPasswordLoginEnable.value = true;
|
isPasswordLoginEnable.value = true;
|
||||||
@ -106,6 +109,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: 'login_form_server_error'.tr(),
|
msg: 'login_form_server_error'.tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
isOauthEnable.value = false;
|
isOauthEnable.value = false;
|
||||||
isPasswordLoginEnable.value = true;
|
isPasswordLoginEnable.value = true;
|
||||||
@ -174,6 +178,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: "login_form_failed_login".tr(),
|
msg: "login_form_failed_login".tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -197,6 +202,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: "login_form_failed_get_oauth_server_config".tr(),
|
msg: "login_form_failed_get_oauth_server_config".tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
return;
|
return;
|
||||||
@ -225,6 +231,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: "login_form_failed_login".tr(),
|
msg: "login_form_failed_login".tr(),
|
||||||
toastType: ToastType.error,
|
toastType: ToastType.error,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,6 +242,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
msg: "login_form_failed_get_oauth_server_disable".tr(),
|
msg: "login_form_failed_get_oauth_server_disable".tr(),
|
||||||
toastType: ToastType.info,
|
toastType: ToastType.info,
|
||||||
|
gravity: ToastGravity.TOP,
|
||||||
);
|
);
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
return;
|
return;
|
||||||
|
@ -7,6 +7,7 @@ import 'package:immich_mobile/shared/services/server_info.service.dart';
|
|||||||
import 'package:immich_mobile/shared/models/server_info/server_config.model.dart';
|
import 'package:immich_mobile/shared/models/server_info/server_config.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/server_info/server_features.model.dart';
|
import 'package:immich_mobile/shared/models/server_info/server_features.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/server_info/server_version.model.dart';
|
import 'package:immich_mobile/shared/models/server_info/server_version.model.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
||||||
@ -47,6 +48,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final ServerInfoService _serverInfoService;
|
final ServerInfoService _serverInfoService;
|
||||||
|
final _log = Logger("ServerInfoNotifier");
|
||||||
|
|
||||||
Future<void> getServerInfo() async {
|
Future<void> getServerInfo() async {
|
||||||
await getServerVersion();
|
await getServerVersion();
|
||||||
@ -55,17 +57,25 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getServerVersion() async {
|
getServerVersion() async {
|
||||||
final serverVersion = await _serverInfoService.getServerVersion();
|
try {
|
||||||
|
final serverVersion = await _serverInfoService.getServerVersion();
|
||||||
|
|
||||||
if (serverVersion == null) {
|
if (serverVersion == null) {
|
||||||
|
state = state.copyWith(
|
||||||
|
isVersionMismatch: true,
|
||||||
|
versionMismatchErrorMessage: "common_server_error".tr(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _checkServerVersionMismatch(serverVersion);
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
_log.severe("Failed to get server version", e, stackTrace);
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
isVersionMismatch: true,
|
isVersionMismatch: true,
|
||||||
versionMismatchErrorMessage: "common_server_error".tr(),
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _checkServerVersionMismatch(serverVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_checkServerVersionMismatch(ServerVersion serverVersion) async {
|
_checkServerVersionMismatch(ServerVersion serverVersion) async {
|
||||||
|
@ -5,6 +5,7 @@ import 'dart:io';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
import 'package:immich_mobile/utils/url_helper.dart';
|
import 'package:immich_mobile/utils/url_helper.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String? _accessToken;
|
String? _accessToken;
|
||||||
|
final _log = Logger("ApiService");
|
||||||
|
|
||||||
setEndpoint(String endpoint) {
|
setEndpoint(String endpoint) {
|
||||||
_apiClient = ApiClient(basePath: endpoint);
|
_apiClient = ApiClient(basePath: endpoint);
|
||||||
@ -95,14 +97,17 @@ class ApiService {
|
|||||||
serverUrl += '/api';
|
serverUrl += '/api';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw Socket or Timeout exceptions,
|
|
||||||
// we do not care if the endpoints hits an HTTP error
|
|
||||||
try {
|
try {
|
||||||
await client
|
final response = await client
|
||||||
.get(
|
.get(Uri.parse("$serverUrl/server-info/ping"))
|
||||||
Uri.parse(serverUrl),
|
|
||||||
)
|
|
||||||
.timeout(const Duration(seconds: 5));
|
.timeout(const Duration(seconds: 5));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
_log.severe(
|
||||||
|
"Server Gateway Error: ${response.body} - Cannot communicate to the server",
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} on TimeoutException catch (_) {
|
} on TimeoutException catch (_) {
|
||||||
return false;
|
return false;
|
||||||
} on SocketException catch (_) {
|
} on SocketException catch (_) {
|
||||||
|
@ -25,20 +25,30 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
void performLoggingIn() async {
|
void performLoggingIn() async {
|
||||||
bool isSuccess = false;
|
bool isSuccess = false;
|
||||||
bool deviceIsOffline = false;
|
bool deviceIsOffline = false;
|
||||||
|
|
||||||
if (accessToken != null && serverUrl != null) {
|
if (accessToken != null && serverUrl != null) {
|
||||||
try {
|
try {
|
||||||
// Resolve API server endpoint from user provided serverUrl
|
// Resolve API server endpoint from user provided serverUrl
|
||||||
await apiService.resolveAndSetEndpoint(serverUrl);
|
await apiService.resolveAndSetEndpoint(serverUrl);
|
||||||
} on ApiException catch (e) {
|
} on ApiException catch (error, stackTrace) {
|
||||||
|
log.severe(
|
||||||
|
"Failed to resolve endpoint [ApiException]",
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
);
|
||||||
// okay, try to continue anyway if offline
|
// okay, try to continue anyway if offline
|
||||||
if (e.code == 503) {
|
if (error.code == 503) {
|
||||||
deviceIsOffline = true;
|
deviceIsOffline = true;
|
||||||
log.fine("Device seems to be offline upon launch");
|
log.warning("Device seems to be offline upon launch");
|
||||||
} else {
|
} else {
|
||||||
log.severe("Failed to resolve endpoint", e);
|
log.severe("Failed to resolve endpoint", error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (error, stackTrace) {
|
||||||
log.severe("Failed to resolve endpoint", e);
|
log.severe(
|
||||||
|
"Failed to resolve endpoint [Catch All]",
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -50,15 +60,11 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
offlineLogin: deviceIsOffline,
|
offlineLogin: deviceIsOffline,
|
||||||
);
|
);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
ref.read(authenticationProvider.notifier).logout();
|
|
||||||
|
|
||||||
log.severe(
|
log.severe(
|
||||||
'Cannot set success login info',
|
'Cannot set success login info',
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stackTrace,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.pushRoute(const LoginRoute());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +82,11 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
context.replaceRoute(const TabControllerRoute());
|
context.replaceRoute(const TabControllerRoute());
|
||||||
} else {
|
} else {
|
||||||
|
log.severe(
|
||||||
|
'Unable to login through offline or online methods - logging out completely',
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.read(authenticationProvider.notifier).logout();
|
||||||
// User was unable to login through either offline or online methods
|
// User was unable to login through either offline or online methods
|
||||||
context.replaceRoute(const LoginRoute());
|
context.replaceRoute(const LoginRoute());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user