Просмотр исходного кода

fix(mobile): freeze on splash screen due to accessing bad state (#998)

Alex 2 лет назад
Родитель
Сommit
56ce747ffc

+ 7 - 4
mobile/lib/modules/login/providers/authentication.provider.dart

@@ -90,6 +90,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
 
       return setSuccessLoginInfo(
         accessToken: loginResponse.accessToken,
+        serverUrl: serverEndpoint,
         isSavedLoginInfo: isSavedLoginInfo,
       );
     } catch (e) {
@@ -159,16 +160,18 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
 
   Future<bool> setSuccessLoginInfo({
     required String accessToken,
+    required String serverUrl,
     required bool isSavedLoginInfo,
   }) async {
-    Hive.box(userInfoBox).put(accessTokenKey, accessToken);
-
     _apiService.setAccessToken(accessToken);
     var userResponseDto = await _apiService.userApi.getMyUserInfo();
 
     if (userResponseDto != null) {
+      var userInfoHiveBox = await Hive.openBox(userInfoBox);
       var deviceInfo = await _deviceInfoService.getDeviceInfo();
-      Hive.box(userInfoBox).put(deviceIdKey, deviceInfo["deviceId"]);
+      userInfoHiveBox.put(deviceIdKey, deviceInfo["deviceId"]);
+      userInfoHiveBox.put(accessTokenKey, accessToken);
+      userInfoHiveBox.put(serverEndpointKey, serverUrl);
 
       state = state.copyWith(
         isAuthenticated: true,
@@ -191,7 +194,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
             email: "",
             password: "",
             isSaveLogin: true,
-            serverUrl: Hive.box(userInfoBox).get(serverEndpointKey),
+            serverUrl: serverUrl,
             accessToken: accessToken,
           ),
         );

+ 1 - 0
mobile/lib/modules/login/ui/login_form.dart

@@ -380,6 +380,7 @@ class OAuthLoginButton extends ConsumerWidget {
               .setSuccessLoginInfo(
                 accessToken: loginResponseDto.accessToken,
                 isSavedLoginInfo: isSavedLoginInfo,
+                serverUrl: serverEndpointController.text,
               );
 
           if (isSuccess) {

+ 20 - 14
mobile/lib/shared/views/splash_screen.dart

@@ -20,22 +20,28 @@ class SplashScreenPage extends HookConsumerWidget {
         Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).get(savedLoginInfoKey);
 
     void performLoggingIn() async {
-      if (loginInfo != null) {
-        // Make sure API service is initialized
-        apiService.setEndpoint(loginInfo.serverUrl);
+      try {
+        if (loginInfo != null) {
+          // Make sure API service is initialized
+          apiService.setEndpoint(loginInfo.serverUrl);
 
-        var isSuccess =
-            await ref.read(authenticationProvider.notifier).setSuccessLoginInfo(
-                  accessToken: loginInfo.accessToken,
-                  isSavedLoginInfo: true,
-                );
-        if (isSuccess) {
-          // Resume backup (if enable) then navigate
-          ref.watch(backupProvider.notifier).resumeBackup();
-          AutoRouter.of(context).replace(const TabControllerRoute());
-        } else {
-          AutoRouter.of(context).replace(const LoginRoute());
+          var isSuccess = await ref
+              .read(authenticationProvider.notifier)
+              .setSuccessLoginInfo(
+                accessToken: loginInfo.accessToken,
+                isSavedLoginInfo: true,
+                serverUrl: loginInfo.serverUrl,
+              );
+          if (isSuccess) {
+            // Resume backup (if enable) then navigate
+            ref.watch(backupProvider.notifier).resumeBackup();
+            AutoRouter.of(context).replace(const TabControllerRoute());
+          } else {
+            AutoRouter.of(context).replace(const LoginRoute());
+          }
         }
+      } catch (_) {
+        AutoRouter.of(context).replace(const LoginRoute());
       }
     }
 

+ 69 - 58
mobile/openapi/lib/model/asset_response_dto.dart

@@ -79,71 +79,74 @@ class AssetResponseDto {
   String? livePhotoVideoId;
 
   @override
-  bool operator ==(Object other) => identical(this, other) || other is AssetResponseDto &&
-     other.type == type &&
-     other.id == id &&
-     other.deviceAssetId == deviceAssetId &&
-     other.ownerId == ownerId &&
-     other.deviceId == deviceId &&
-     other.originalPath == originalPath &&
-     other.resizePath == resizePath &&
-     other.createdAt == createdAt &&
-     other.modifiedAt == modifiedAt &&
-     other.isFavorite == isFavorite &&
-     other.mimeType == mimeType &&
-     other.duration == duration &&
-     other.webpPath == webpPath &&
-     other.encodedVideoPath == encodedVideoPath &&
-     other.exifInfo == exifInfo &&
-     other.smartInfo == smartInfo &&
-     other.livePhotoVideoId == livePhotoVideoId;
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is AssetResponseDto &&
+          other.type == type &&
+          other.id == id &&
+          other.deviceAssetId == deviceAssetId &&
+          other.ownerId == ownerId &&
+          other.deviceId == deviceId &&
+          other.originalPath == originalPath &&
+          other.resizePath == resizePath &&
+          other.createdAt == createdAt &&
+          other.modifiedAt == modifiedAt &&
+          other.isFavorite == isFavorite &&
+          other.mimeType == mimeType &&
+          other.duration == duration &&
+          other.webpPath == webpPath &&
+          other.encodedVideoPath == encodedVideoPath &&
+          other.exifInfo == exifInfo &&
+          other.smartInfo == smartInfo &&
+          other.livePhotoVideoId == livePhotoVideoId;
 
   @override
   int get hashCode =>
-    // ignore: unnecessary_parenthesis
-    (type.hashCode) +
-    (id.hashCode) +
-    (deviceAssetId.hashCode) +
-    (ownerId.hashCode) +
-    (deviceId.hashCode) +
-    (originalPath.hashCode) +
-    (resizePath == null ? 0 : resizePath!.hashCode) +
-    (createdAt.hashCode) +
-    (modifiedAt.hashCode) +
-    (isFavorite.hashCode) +
-    (mimeType == null ? 0 : mimeType!.hashCode) +
-    (duration.hashCode) +
-    (webpPath == null ? 0 : webpPath!.hashCode) +
-    (encodedVideoPath == null ? 0 : encodedVideoPath!.hashCode) +
-    (exifInfo == null ? 0 : exifInfo!.hashCode) +
-    (smartInfo == null ? 0 : smartInfo!.hashCode) +
-    (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode);
+      // ignore: unnecessary_parenthesis
+      (type.hashCode) +
+      (id.hashCode) +
+      (deviceAssetId.hashCode) +
+      (ownerId.hashCode) +
+      (deviceId.hashCode) +
+      (originalPath.hashCode) +
+      (resizePath == null ? 0 : resizePath!.hashCode) +
+      (createdAt.hashCode) +
+      (modifiedAt.hashCode) +
+      (isFavorite.hashCode) +
+      (mimeType == null ? 0 : mimeType!.hashCode) +
+      (duration.hashCode) +
+      (webpPath == null ? 0 : webpPath!.hashCode) +
+      (encodedVideoPath == null ? 0 : encodedVideoPath!.hashCode) +
+      (exifInfo == null ? 0 : exifInfo!.hashCode) +
+      (smartInfo == null ? 0 : smartInfo!.hashCode) +
+      (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode);
 
   @override
-  String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId]';
+  String toString() =>
+      'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId]';
 
   Map<String, dynamic> toJson() {
     final _json = <String, dynamic>{};
-      _json[r'type'] = type;
-      _json[r'id'] = id;
-      _json[r'deviceAssetId'] = deviceAssetId;
-      _json[r'ownerId'] = ownerId;
-      _json[r'deviceId'] = deviceId;
-      _json[r'originalPath'] = originalPath;
+    _json[r'type'] = type;
+    _json[r'id'] = id;
+    _json[r'deviceAssetId'] = deviceAssetId;
+    _json[r'ownerId'] = ownerId;
+    _json[r'deviceId'] = deviceId;
+    _json[r'originalPath'] = originalPath;
     if (resizePath != null) {
       _json[r'resizePath'] = resizePath;
     } else {
       _json[r'resizePath'] = null;
     }
-      _json[r'createdAt'] = createdAt;
-      _json[r'modifiedAt'] = modifiedAt;
-      _json[r'isFavorite'] = isFavorite;
+    _json[r'createdAt'] = createdAt;
+    _json[r'modifiedAt'] = modifiedAt;
+    _json[r'isFavorite'] = isFavorite;
     if (mimeType != null) {
       _json[r'mimeType'] = mimeType;
     } else {
       _json[r'mimeType'] = null;
     }
-      _json[r'duration'] = duration;
+    _json[r'duration'] = duration;
     if (webpPath != null) {
       _json[r'webpPath'] = webpPath;
     } else {
@@ -182,13 +185,13 @@ class AssetResponseDto {
       // Ensure that the map contains the required keys.
       // Note 1: the values aren't checked for validity beyond being non-null.
       // Note 2: this code is stripped in release mode!
-      assert(() {
-        requiredKeys.forEach((key) {
-          assert(json.containsKey(key), 'Required key "AssetResponseDto[$key]" is missing from JSON.');
-          assert(json[key] != null, 'Required key "AssetResponseDto[$key]" has a null value in JSON.');
-        });
-        return true;
-      }());
+      // assert(() {
+      //   requiredKeys.forEach((key) {
+      //     assert(json.containsKey(key), 'Required key "AssetResponseDto[$key]" is missing from JSON.');
+      //     assert(json[key] != null, 'Required key "AssetResponseDto[$key]" has a null value in JSON.');
+      //   });
+      //   return true;
+      // }());
 
       return AssetResponseDto(
         type: AssetTypeEnum.fromJson(json[r'type'])!,
@@ -213,7 +216,10 @@ class AssetResponseDto {
     return null;
   }
 
-  static List<AssetResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
+  static List<AssetResponseDto>? listFromJson(
+    dynamic json, {
+    bool growable = false,
+  }) {
     final result = <AssetResponseDto>[];
     if (json is List && json.isNotEmpty) {
       for (final row in json) {
@@ -241,12 +247,18 @@ class AssetResponseDto {
   }
 
   // maps a json object with a list of AssetResponseDto-objects as value to a dart map
-  static Map<String, List<AssetResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
+  static Map<String, List<AssetResponseDto>> mapListFromJson(
+    dynamic json, {
+    bool growable = false,
+  }) {
     final map = <String, List<AssetResponseDto>>{};
     if (json is Map && json.isNotEmpty) {
       json = json.cast<String, dynamic>(); // ignore: parameter_assignments
       for (final entry in json.entries) {
-        final value = AssetResponseDto.listFromJson(entry.value, growable: growable,);
+        final value = AssetResponseDto.listFromJson(
+          entry.value,
+          growable: growable,
+        );
         if (value != null) {
           map[entry.key] = value;
         }
@@ -274,4 +286,3 @@ class AssetResponseDto {
     'livePhotoVideoId',
   };
 }
-

+ 53 - 41
mobile/openapi/lib/model/user_response_dto.dart

@@ -43,43 +43,46 @@ class UserResponseDto {
   DateTime? deletedAt;
 
   @override
-  bool operator ==(Object other) => identical(this, other) || other is UserResponseDto &&
-     other.id == id &&
-     other.email == email &&
-     other.firstName == firstName &&
-     other.lastName == lastName &&
-     other.createdAt == createdAt &&
-     other.profileImagePath == profileImagePath &&
-     other.shouldChangePassword == shouldChangePassword &&
-     other.isAdmin == isAdmin &&
-     other.deletedAt == deletedAt;
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is UserResponseDto &&
+          other.id == id &&
+          other.email == email &&
+          other.firstName == firstName &&
+          other.lastName == lastName &&
+          other.createdAt == createdAt &&
+          other.profileImagePath == profileImagePath &&
+          other.shouldChangePassword == shouldChangePassword &&
+          other.isAdmin == isAdmin &&
+          other.deletedAt == deletedAt;
 
   @override
   int get hashCode =>
-    // ignore: unnecessary_parenthesis
-    (id.hashCode) +
-    (email.hashCode) +
-    (firstName.hashCode) +
-    (lastName.hashCode) +
-    (createdAt.hashCode) +
-    (profileImagePath.hashCode) +
-    (shouldChangePassword.hashCode) +
-    (isAdmin.hashCode) +
-    (deletedAt == null ? 0 : deletedAt!.hashCode);
+      // ignore: unnecessary_parenthesis
+      (id.hashCode) +
+      (email.hashCode) +
+      (firstName.hashCode) +
+      (lastName.hashCode) +
+      (createdAt.hashCode) +
+      (profileImagePath.hashCode) +
+      (shouldChangePassword.hashCode) +
+      (isAdmin.hashCode) +
+      (deletedAt == null ? 0 : deletedAt!.hashCode);
 
   @override
-  String toString() => 'UserResponseDto[id=$id, email=$email, firstName=$firstName, lastName=$lastName, createdAt=$createdAt, profileImagePath=$profileImagePath, shouldChangePassword=$shouldChangePassword, isAdmin=$isAdmin, deletedAt=$deletedAt]';
+  String toString() =>
+      'UserResponseDto[id=$id, email=$email, firstName=$firstName, lastName=$lastName, createdAt=$createdAt, profileImagePath=$profileImagePath, shouldChangePassword=$shouldChangePassword, isAdmin=$isAdmin, deletedAt=$deletedAt]';
 
   Map<String, dynamic> toJson() {
     final _json = <String, dynamic>{};
-      _json[r'id'] = id;
-      _json[r'email'] = email;
-      _json[r'firstName'] = firstName;
-      _json[r'lastName'] = lastName;
-      _json[r'createdAt'] = createdAt;
-      _json[r'profileImagePath'] = profileImagePath;
-      _json[r'shouldChangePassword'] = shouldChangePassword;
-      _json[r'isAdmin'] = isAdmin;
+    _json[r'id'] = id;
+    _json[r'email'] = email;
+    _json[r'firstName'] = firstName;
+    _json[r'lastName'] = lastName;
+    _json[r'createdAt'] = createdAt;
+    _json[r'profileImagePath'] = profileImagePath;
+    _json[r'shouldChangePassword'] = shouldChangePassword;
+    _json[r'isAdmin'] = isAdmin;
     if (deletedAt != null) {
       _json[r'deletedAt'] = deletedAt!.toUtc().toIso8601String();
     } else {
@@ -98,13 +101,13 @@ class UserResponseDto {
       // Ensure that the map contains the required keys.
       // Note 1: the values aren't checked for validity beyond being non-null.
       // Note 2: this code is stripped in release mode!
-      assert(() {
-        requiredKeys.forEach((key) {
-          assert(json.containsKey(key), 'Required key "UserResponseDto[$key]" is missing from JSON.');
-          assert(json[key] != null, 'Required key "UserResponseDto[$key]" has a null value in JSON.');
-        });
-        return true;
-      }());
+      // assert(() {
+      //   requiredKeys.forEach((key) {
+      //     assert(json.containsKey(key), 'Required key "UserResponseDto[$key]" is missing from JSON.');
+      //     assert(json[key] != null, 'Required key "UserResponseDto[$key]" has a null value in JSON.');
+      //   });
+      //   return true;
+      // }());
 
       return UserResponseDto(
         id: mapValueOfType<String>(json, r'id')!,
@@ -113,7 +116,8 @@ class UserResponseDto {
         lastName: mapValueOfType<String>(json, r'lastName')!,
         createdAt: mapValueOfType<String>(json, r'createdAt')!,
         profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
-        shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
+        shouldChangePassword:
+            mapValueOfType<bool>(json, r'shouldChangePassword')!,
         isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
         deletedAt: mapDateTime(json, r'deletedAt', ''),
       );
@@ -121,7 +125,10 @@ class UserResponseDto {
     return null;
   }
 
-  static List<UserResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
+  static List<UserResponseDto>? listFromJson(
+    dynamic json, {
+    bool growable = false,
+  }) {
     final result = <UserResponseDto>[];
     if (json is List && json.isNotEmpty) {
       for (final row in json) {
@@ -149,12 +156,18 @@ class UserResponseDto {
   }
 
   // maps a json object with a list of UserResponseDto-objects as value to a dart map
-  static Map<String, List<UserResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
+  static Map<String, List<UserResponseDto>> mapListFromJson(
+    dynamic json, {
+    bool growable = false,
+  }) {
     final map = <String, List<UserResponseDto>>{};
     if (json is Map && json.isNotEmpty) {
       json = json.cast<String, dynamic>(); // ignore: parameter_assignments
       for (final entry in json.entries) {
-        final value = UserResponseDto.listFromJson(entry.value, growable: growable,);
+        final value = UserResponseDto.listFromJson(
+          entry.value,
+          growable: growable,
+        );
         if (value != null) {
           map[entry.key] = value;
         }
@@ -176,4 +189,3 @@ class UserResponseDto {
     'deletedAt',
   };
 }
-