Browse Source

Surface network error on UI + show contact support in generic err dialog (#1548)

Neeraj Gupta 1 year ago
parent
commit
8e8ac25a66
40 changed files with 212 additions and 85 deletions
  1. 2 0
      lib/core/constants.dart
  2. 4 0
      lib/generated/intl/messages_en.dart
  3. 20 0
      lib/generated/l10n.dart
  4. 2 0
      lib/l10n/intl_en.arb
  5. 1 1
      lib/models/search/search_types.dart
  6. 1 1
      lib/services/billing_service.dart
  7. 2 1
      lib/services/feature_flag_service.dart
  8. 1 1
      lib/services/hidden_service.dart
  9. 11 8
      lib/services/user_service.dart
  10. 2 2
      lib/ui/account/delete_account_page.dart
  11. 3 3
      lib/ui/account/password_entry_page.dart
  12. 2 2
      lib/ui/account/verify_recovery_page.dart
  13. 2 2
      lib/ui/actions/collection/collection_file_actions.dart
  14. 7 7
      lib/ui/actions/collection/collection_sharing_actions.dart
  15. 1 1
      lib/ui/actions/file/file_actions.dart
  16. 9 5
      lib/ui/collections/album/vertical_list.dart
  17. 1 1
      lib/ui/collections/new_album_icon.dart
  18. 1 1
      lib/ui/components/buttons/button_widget.dart
  19. 1 1
      lib/ui/home/memories/full_screen_memory.dart
  20. 1 1
      lib/ui/payment/child_subscription_widget.dart
  21. 4 1
      lib/ui/payment/payment_web_page.dart
  22. 7 4
      lib/ui/payment/store_subscription_page.dart
  23. 1 1
      lib/ui/payment/stripe_subscription_page.dart
  24. 1 1
      lib/ui/settings/backup/backup_folder_selection_page.dart
  25. 2 2
      lib/ui/settings/backup/backup_section_widget.dart
  26. 15 7
      lib/ui/settings/security_section_widget.dart
  27. 1 1
      lib/ui/sharing/manage_album_participant.dart
  28. 1 1
      lib/ui/sharing/manage_links_widget.dart
  29. 1 1
      lib/ui/sharing/pickers/device_limit_picker_page.dart
  30. 1 1
      lib/ui/sharing/pickers/link_expiry_picker_page.dart
  31. 3 3
      lib/ui/viewer/file/file_app_bar.dart
  32. 1 1
      lib/ui/viewer/gallery/empty_album_state.dart
  33. 7 7
      lib/ui/viewer/gallery/gallery_app_bar_widget.dart
  34. 1 1
      lib/ui/viewer/location/location_screen.dart
  35. 1 1
      lib/ui/viewer/location/radius_picker_widget.dart
  36. 12 6
      lib/utils/delete_file_util.dart
  37. 76 5
      lib/utils/dialog_util.dart
  38. 1 1
      lib/utils/magic_util.dart
  39. 1 1
      lib/utils/share_util.dart
  40. 1 1
      pubspec.yaml

+ 2 - 0
lib/core/constants.dart

@@ -64,3 +64,5 @@ const defaultRadiusValue = 40.0;
 const galleryGridSpacing = 2.0;
 
 const searchSectionLimit = 7;
+
+bool isInternalUser = false;

+ 4 - 0
lib/generated/intl/messages_en.dart

@@ -869,6 +869,10 @@ class MessageLookup extends MessageLookupByLibrary {
         "movingFilesToAlbum":
             MessageLookupByLibrary.simpleMessage("Moving files to album..."),
         "name": MessageLookupByLibrary.simpleMessage("Name"),
+        "networkConnectionRefusedErr": MessageLookupByLibrary.simpleMessage(
+            "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support."),
+        "networkHostLookUpErr": MessageLookupByLibrary.simpleMessage(
+            "Unable to connect to Ente, please check your network settings and contact support if the error persists."),
         "never": MessageLookupByLibrary.simpleMessage("Never"),
         "newAlbum": MessageLookupByLibrary.simpleMessage("New album"),
         "newToEnte": MessageLookupByLibrary.simpleMessage("New to ente"),

+ 20 - 0
lib/generated/l10n.dart

@@ -6529,6 +6529,26 @@ class S {
     );
   }
 
+  /// `Unable to connect to Ente, please check your network settings and contact support if the error persists.`
+  String get networkHostLookUpErr {
+    return Intl.message(
+      'Unable to connect to Ente, please check your network settings and contact support if the error persists.',
+      name: 'networkHostLookUpErr',
+      desc: '',
+      args: [],
+    );
+  }
+
+  /// `Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.`
+  String get networkConnectionRefusedErr {
+    return Intl.message(
+      'Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.',
+      name: 'networkConnectionRefusedErr',
+      desc: '',
+      args: [],
+    );
+  }
+
   /// `Cached data`
   String get cachedData {
     return Intl.message(

+ 2 - 0
lib/l10n/intl_en.arb

@@ -929,6 +929,8 @@
   "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
   "error": "Error",
   "tempErrorContactSupportIfPersists": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
+  "networkHostLookUpErr" : "Unable to connect to Ente, please check your network settings and contact support if the error persists.",
+  "networkConnectionRefusedErr" : "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.",
   "cachedData": "Cached data",
   "clearCaches": "Clear caches",
   "remoteImages": "Remote images",

+ 1 - 1
lib/models/search/search_types.dart

@@ -222,7 +222,7 @@ extension SectionTypeExtensions on SectionType {
             },
           );
           if (result is Exception) {
-            showGenericErrorDialog(context: context);
+            showGenericErrorDialog(context: context, error: result);
           }
         };
       default:

+ 1 - 1
lib/services/billing_service.dart

@@ -196,7 +196,7 @@ class BillingService {
       );
     } catch (e) {
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
     await dialog.hide();
   }

+ 2 - 1
lib/services/feature_flag_service.dart

@@ -71,9 +71,10 @@ class FeatureFlagService {
   bool isInternalUserOrDebugBuild() {
     final String? email = Configuration.instance.getEmail();
     final userID = Configuration.instance.getUserID();
-    return (email != null && email.endsWith("@ente.io")) ||
+    isInternalUser = (email != null && email.endsWith("@ente.io")) ||
         _internalUserIDs.contains(userID) ||
         kDebugMode;
+    return isInternalUser;
   }
 
   Future<void> fetchFeatureFlags() async {

+ 1 - 1
lib/services/hidden_service.dart

@@ -154,7 +154,7 @@ extension HiddenService on CollectionsService {
     } catch (e, s) {
       _logger.severe("Could not hide", e, s);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return false;
     } finally {
       await dialog.hide();

+ 11 - 8
lib/services/user_service.dart

@@ -113,8 +113,9 @@ class UserService {
           ),
         );
         return;
+      } else {
+        throw Exception("send-ott action failed, non-200");
       }
-      unawaited(showGenericErrorDialog(context: context));
     } on DioError catch (e) {
       await dialog.hide();
       _logger.info(e);
@@ -127,12 +128,14 @@ class UserService {
           ),
         );
       } else {
-        unawaited(showGenericErrorDialog(context: context));
+        unawaited(showGenericErrorDialog(context: context, error: e));
       }
-    } catch (e) {
+    } catch (e, s) {
       await dialog.hide();
-      _logger.severe(e);
-      unawaited(showGenericErrorDialog(context: context));
+      _logger.severe(e, s);
+      unawaited(
+        showGenericErrorDialog(context: context, error: e),
+      );
     }
   }
 
@@ -259,7 +262,7 @@ class UserService {
       //to close and only then to show the error dialog.
       Future.delayed(
         const Duration(milliseconds: 150),
-        () => showGenericErrorDialog(context: context),
+        () => showGenericErrorDialog(context: context, error: null),
       );
     }
   }
@@ -279,7 +282,7 @@ class UserService {
       }
     } catch (e) {
       _logger.severe(e);
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: e);
       return null;
     }
   }
@@ -956,7 +959,7 @@ class UserService {
     try {
       recoveryKey = await getOrCreateRecoveryKey(context);
     } catch (e) {
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return false;
     }
     final dialog = createProgressDialog(context, S.of(context).verifying);

+ 2 - 2
lib/ui/account/delete_account_page.dart

@@ -262,7 +262,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
       isDismissible: false,
     );
     if (choice!.action == ButtonAction.error) {
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: choice.exception);
     }
   }
 
@@ -289,7 +289,7 @@ class _DeleteAccountPageState extends State<DeleteAccountPage> {
       showShortToast(context, S.of(context).yourAccountHasBeenDeleted);
     } catch (e, s) {
       Logger("DeleteAccount").severe("failed to delete", e, s);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 

+ 3 - 3
lib/ui/account/password_entry_page.dart

@@ -404,7 +404,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
     } catch (e, s) {
       _logger.severe(e, s);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 
@@ -456,7 +456,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
         } catch (e, s) {
           _logger.severe(e, s);
           await dialog.hide();
-          showGenericErrorDialog(context: context);
+          showGenericErrorDialog(context: context, error: e);
         }
       }
 
@@ -481,7 +481,7 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
           S.of(context).sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease,
         );
       } else {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: e);
       }
     }
   }

+ 2 - 2
lib/ui/account/verify_recovery_page.dart

@@ -51,7 +51,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
               "Please check your internet connection and try again.",
             );
           } else {
-            await showGenericErrorDialog(context: context);
+            await showGenericErrorDialog(context: context, error: e);
           }
           return;
         }
@@ -109,7 +109,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
           ),
         );
       } catch (e) {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: e);
         return;
       }
     }

+ 2 - 2
lib/ui/actions/collection/collection_file_actions.dart

@@ -73,7 +73,7 @@ extension CollectionFileActions on CollectionActions {
     );
     if (actionResult?.action != null &&
         actionResult!.action == ButtonAction.error) {
-      showGenericErrorDialog(context: bContext);
+      showGenericErrorDialog(context: bContext, error: actionResult.exception);
     } else {
       selectedFiles.clearAll();
     }
@@ -187,7 +187,7 @@ extension CollectionFileActions on CollectionActions {
     } catch (e, s) {
       logger.severe("Failed to add to album", e, s);
       await dialog?.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       rethrow;
     }
   }

+ 7 - 7
lib/ui/actions/collection/collection_sharing_actions.dart

@@ -52,7 +52,7 @@ class CollectionActions {
         _showUnSupportedAlert(context);
       } else {
         logger.severe("Failed to update shareUrl collection", e);
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: e);
       }
       return false;
     }
@@ -93,7 +93,7 @@ class CollectionActions {
     );
     if (actionResult?.action != null) {
       if (actionResult!.action == ButtonAction.error) {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: actionResult.exception);
       }
       return actionResult.action == ButtonAction.first;
     } else {
@@ -142,7 +142,7 @@ class CollectionActions {
       return collection;
     } catch (e, s) {
       dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       logger.severe("Failing to create link for selected files", e, s);
     }
     return null;
@@ -183,7 +183,7 @@ class CollectionActions {
     );
     if (actionResult?.action != null) {
       if (actionResult!.action == ButtonAction.error) {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: actionResult.exception);
       }
       return actionResult.action == ButtonAction.first;
     }
@@ -230,7 +230,7 @@ class CollectionActions {
     } catch (e) {
       await dialog?.hide();
       logger.severe("Failed to get public key", e);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return false;
     }
     // getPublicKey can return null when no user is associated with given
@@ -272,7 +272,7 @@ class CollectionActions {
           _showUnSupportedAlert(context);
         } else {
           logger.severe("failed to share collection", e);
-          showGenericErrorDialog(context: context);
+          showGenericErrorDialog(context: context, error: e);
         }
         return false;
       }
@@ -353,7 +353,7 @@ class CollectionActions {
     );
     if (actionResult?.action != null &&
         actionResult!.action == ButtonAction.error) {
-      showGenericErrorDialog(context: bContext);
+      showGenericErrorDialog(context: bContext, error: actionResult.exception);
       return false;
     }
     if ((actionResult?.action != null) &&

+ 1 - 1
lib/ui/actions/file/file_actions.dart

@@ -125,7 +125,7 @@ Future<void> showSingleFileDeleteSheet(
   );
   if (actionResult?.action != null &&
       actionResult!.action == ButtonAction.error) {
-    showGenericErrorDialog(context: context);
+    showGenericErrorDialog(context: context, error: actionResult.exception);
   }
 }
 

+ 9 - 5
lib/ui/collections/album/vertical_list.dart

@@ -111,6 +111,7 @@ class AlbumVerticalListWidget extends StatelessWidget {
       if (result is Exception) {
         showGenericErrorDialog(
           context: context,
+          error: result,
         );
         _logger.severe(
           "Failed to name album",
@@ -310,7 +311,7 @@ class AlbumVerticalListWidget extends StatelessWidget {
           );
           return true;
         } catch (e) {
-          showGenericErrorDialog(context: context);
+          showGenericErrorDialog(context: context, error: e);
           return false;
         }
       }
@@ -333,7 +334,7 @@ class AlbumVerticalListWidget extends StatelessWidget {
           ),
         );
       } else {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: result);
         _logger.severe("Cannot share collections owned by others");
       }
     }
@@ -352,7 +353,10 @@ class AlbumVerticalListWidget extends StatelessWidget {
         ),
       );
     } else {
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(
+        context: context,
+        error: Exception("Can not share collection owned by others"),
+      );
       _logger.severe("Cannot share collections owned by others");
     }
     return Future.value(true);
@@ -409,7 +413,7 @@ class AlbumVerticalListWidget extends StatelessWidget {
     } catch (e, s) {
       _logger.severe("Could not move to album", e, s);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return false;
     }
   }
@@ -438,7 +442,7 @@ class AlbumVerticalListWidget extends StatelessWidget {
     } catch (e, s) {
       _logger.severe("Could not move to album", e, s);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return false;
     }
   }

+ 1 - 1
lib/ui/collections/new_album_icon.dart

@@ -55,7 +55,7 @@ class NewAlbumIcon extends StatelessWidget {
           },
         );
         if (result is Exception) {
-          showGenericErrorDialog(context: context);
+          showGenericErrorDialog(context: context, error: result);
         }
       },
     );

+ 1 - 1
lib/ui/components/buttons/button_widget.dart

@@ -498,7 +498,7 @@ class _ButtonChildWidgetState extends State<ButtonChildWidget> {
       } else if (exception != null) {
         //This is to show the execution was unsuccessful if the dialog is manually
         //closed before the execution completes.
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: exception);
       }
     }
   }

+ 1 - 1
lib/ui/home/memories/full_screen_memory.dart

@@ -36,7 +36,7 @@ class _FullScreenMemoryState extends State<FullScreenMemory> {
   bool _showCounter = false;
   bool _showStepIndicator = true;
   PageController? _pageController;
-  bool _shouldDisableScroll = false;
+  final bool _shouldDisableScroll = false;
   late int currentUserID;
   final GlobalKey shareButtonKey = GlobalKey();
 

+ 1 - 1
lib/ui/payment/child_subscription_widget.dart

@@ -123,7 +123,7 @@ class ChildSubscriptionWidget extends StatelessWidget {
       },
     );
     if (choice!.action == ButtonAction.error) {
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: choice.exception);
     }
   }
 }

+ 4 - 1
lib/ui/payment/payment_web_page.dart

@@ -190,7 +190,10 @@ class _PaymentWebPageState extends State<PaymentWebPage> {
     } else {
       // should never reach here
       _logger.severe("unexpected status", uri.toString());
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(
+        context: context,
+        error: Exception("expected payment status $paymentStatus"),
+      );
     }
   }
 

+ 7 - 4
lib/ui/payment/store_subscription_page.dart

@@ -524,11 +524,14 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
               final ProductDetailsResponse response =
                   await InAppPurchase.instance.queryProductDetails({productID});
               if (response.notFoundIDs.isNotEmpty) {
-                _logger.severe(
-                  "Could not find products: " + response.notFoundIDs.toString(),
-                );
+                final errMsg = "Could not find products: " +
+                    response.notFoundIDs.toString();
+                _logger.severe(errMsg);
                 await _dialog.hide();
-                showGenericErrorDialog(context: context);
+                showGenericErrorDialog(
+                  context: context,
+                  error: Exception(errMsg),
+                );
                 return;
               }
               final isCrossGradingOnAndroid = Platform.isAndroid &&

+ 1 - 1
lib/ui/payment/stripe_subscription_page.dart

@@ -337,7 +337,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
       ).then((value) => onWebPaymentGoBack);
     } catch (e) {
       await _dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
     await _dialog.hide();
   }

+ 1 - 1
lib/ui/settings/backup/backup_folder_selection_page.dart

@@ -232,7 +232,7 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
     } catch (e, s) {
       _logger.severe("Failed to updated backup folder", e, s);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 

+ 2 - 2
lib/ui/settings/backup/backup_section_widget.dart

@@ -94,7 +94,7 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
             try {
               status = await SyncService.instance.getBackupStatus();
             } catch (e) {
-              showGenericErrorDialog(context: context);
+              showGenericErrorDialog(context: context, error: e);
               return;
             }
 
@@ -128,7 +128,7 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
               duplicates =
                   await DeduplicationService.instance.getDuplicateFiles();
             } catch (e) {
-              showGenericErrorDialog(context: context);
+              showGenericErrorDialog(context: context, error: e);
               return;
             }
 

+ 15 - 7
lib/ui/settings/security_section_widget.dart

@@ -89,7 +89,7 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
                 try {
                   recoveryKey = await _getOrCreateRecoveryKey(context);
                 } catch (e) {
-                  await showGenericErrorDialog(context: context);
+                  await showGenericErrorDialog(context: context, error: e);
                   return;
                 }
                 unawaited(
@@ -260,14 +260,22 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
       await UserService.instance.getOrCreateRecoveryKey(context),
     );
   }
+
   Future<void> updateEmailMFA(bool isEnabled) async {
     try {
-      final UserDetails details = await UserService.instance.getUserDetailsV2(memoryCount: false);
-      if((details.profileData?.canDisableEmailMFA ?? false) == false) {
-        await routeToPage(context, RequestPasswordVerificationPage(onPasswordVerified: (Uint8List keyEncryptionKey) async {
-          final Uint8List loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey);
-          await UserService.instance.registerOrUpdateSrp(loginKey);
-        },),);
+      final UserDetails details =
+          await UserService.instance.getUserDetailsV2(memoryCount: false);
+      if ((details.profileData?.canDisableEmailMFA ?? false) == false) {
+        await routeToPage(
+          context,
+          RequestPasswordVerificationPage(
+            onPasswordVerified: (Uint8List keyEncryptionKey) async {
+              final Uint8List loginKey =
+                  await CryptoUtil.deriveLoginKey(keyEncryptionKey);
+              await UserService.instance.registerOrUpdateSrp(loginKey);
+            },
+          ),
+        );
       }
       await UserService.instance.updateEmailMFA(isEnabled);
     } catch (e) {

+ 1 - 1
lib/ui/sharing/manage_album_participant.dart

@@ -132,7 +132,7 @@ class _ManageIndividualParticipantState
                               CollectionParticipantRole.viewer,
                             );
                           } catch (e) {
-                            showGenericErrorDialog(context: context);
+                            showGenericErrorDialog(context: context, error: e);
                           }
                           if (isConvertToViewSuccess && mounted) {
                             // reset value

+ 1 - 1
lib/ui/sharing/manage_links_widget.dart

@@ -347,7 +347,7 @@ class _ManageSharedLinkWidgetState extends State<ManageSharedLinkWidget> {
       }
     } catch (e) {
       await dialog?.hide();
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: e);
       rethrow;
     }
   }

+ 1 - 1
lib/ui/sharing/pickers/device_limit_picker_page.dart

@@ -137,7 +137,7 @@ class _ItemsWidgetState extends State<ItemsWidget> {
     try {
       await CollectionsService.instance.updateShareUrl(widget.collection, prop);
     } catch (e) {
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       rethrow;
     }
   }

+ 1 - 1
lib/ui/sharing/pickers/link_expiry_picker_page.dart

@@ -180,7 +180,7 @@ class _ItemsWidgetState extends State<ItemsWidget> {
     try {
       await CollectionsService.instance.updateShareUrl(widget.collection, prop);
     } catch (e) {
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       rethrow;
     }
   }

+ 3 - 3
lib/ui/viewer/file/file_app_bar.dart

@@ -288,7 +288,7 @@ class FileAppBarState extends State<FileAppBar> {
       }
     } catch (e, s) {
       _logger.severe("failed to update file visibility", e, s);
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: e);
     }
   }
 
@@ -371,7 +371,7 @@ class FileAppBarState extends State<FileAppBar> {
     } catch (e) {
       _logger.warning("Failed to save file", e);
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     } finally {
       PhotoManager.startChangeNotify();
       LocalSyncService.instance.checkAndSync().ignore();
@@ -432,7 +432,7 @@ class FileAppBarState extends State<FileAppBar> {
     } catch (e) {
       dialog.hide();
       _logger.severe("Failed to use as", e);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 }

+ 1 - 1
lib/ui/viewer/gallery/empty_album_state.dart

@@ -31,7 +31,7 @@ class EmptyAlbumState extends StatelessWidget {
               try {
                 await showAddPhotosSheet(context, c);
               } catch (e) {
-                showGenericErrorDialog(context: context);
+                showGenericErrorDialog(context: context, error: e);
               }
             },
           ),

+ 7 - 7
lib/ui/viewer/gallery/gallery_app_bar_widget.dart

@@ -172,7 +172,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       },
     );
     if (result is Exception) {
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: result);
     }
   }
 
@@ -204,7 +204,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     );
     if (actionResult?.action != null && mounted) {
       if (actionResult!.action == ButtonAction.error) {
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: actionResult.exception);
       } else if (actionResult.action == ButtonAction.first) {
         Navigator.of(context).pop();
       }
@@ -224,7 +224,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
           .getBackupStatus(pathID: widget.deviceCollection!.id);
     } catch (e) {
       await dialog.hide();
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       return;
     }
 
@@ -664,7 +664,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       } catch (e, s) {
         _logger.severe("failed to trash collection", e, s);
         await dialog.hide();
-        showGenericErrorDialog(context: context);
+        showGenericErrorDialog(context: context, error: e);
       }
     } else {
       final bool result = await collectionActions.deleteCollectionSheet(
@@ -691,7 +691,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       }
     } catch (e, s) {
       _logger.severe("failed to trash collection", e, s);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 
@@ -726,7 +726,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       }
     } catch (e, s) {
       _logger.severe(e, s);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
     }
   }
 
@@ -736,7 +736,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       await showAddPhotosSheet(bContext, collection!);
     } catch (e, s) {
       _logger.severe(e, s);
-      showGenericErrorDialog(context: bContext);
+      showGenericErrorDialog(context: bContext, error: e);
     }
   }
 

+ 1 - 1
lib/ui/viewer/location/location_screen.dart

@@ -118,7 +118,7 @@ class LocationScreenPopUpMenu extends StatelessWidget {
                 );
                 Navigator.of(context).pop();
               } catch (e) {
-                showGenericErrorDialog(context: context);
+                showGenericErrorDialog(context: context, error: e);
               }
             }
           },

+ 1 - 1
lib/ui/viewer/location/radius_picker_widget.dart

@@ -200,7 +200,7 @@ class _RadiusPickerWidgetState extends State<RadiusPickerWidget> {
       alignMessage: Alignment.centerRight,
     );
     if (result is Exception) {
-      await showGenericErrorDialog(context: context);
+      await showGenericErrorDialog(context: context, error: result);
       _logger.severe(
         "Failed to create custom radius",
         result,

+ 12 - 6
lib/utils/delete_file_util.dart

@@ -102,7 +102,7 @@ Future<void> deleteFilesFromEverywhere(
       await FilesDB.instance.deleteMultipleUploadedFiles(fileIDs);
     } catch (e) {
       _logger.severe(e);
-      showGenericErrorDialog(context: context);
+      showGenericErrorDialog(context: context, error: e);
       rethrow;
     }
     for (final collectionID in updatedCollectionIDs) {
@@ -163,7 +163,7 @@ Future<void> deleteFilesFromRemoteOnly(
     await FilesDB.instance.deleteMultipleUploadedFiles(uploadedFileIDs);
   } catch (e, s) {
     _logger.severe("Failed to delete files from remote", e, s);
-    showGenericErrorDialog(context: context);
+    showGenericErrorDialog(context: context, error: e);
     rethrow;
   }
   for (final collectionID in updatedCollectionIDs) {
@@ -279,7 +279,10 @@ Future<bool> deleteFromTrash(BuildContext context, List<EnteFile> files) async {
       actionResult!.action == ButtonAction.cancel) {
     return didDeletionStart ? true : false;
   } else if (actionResult.action == ButtonAction.error) {
-    await showGenericErrorDialog(context: context);
+    await showGenericErrorDialog(
+      context: context,
+      error: actionResult.exception,
+    );
     return false;
   } else {
     return true;
@@ -306,7 +309,10 @@ Future<bool> emptyTrash(BuildContext context) async {
       actionResult!.action == ButtonAction.cancel) {
     return false;
   } else if (actionResult.action == ButtonAction.error) {
-    await showGenericErrorDialog(context: context);
+    await showGenericErrorDialog(
+      context: context,
+      error: actionResult.exception,
+    );
     return false;
   } else {
     return true;
@@ -555,7 +561,7 @@ Future<void> showDeleteSheet(
               showShortToast(context, S.of(context).movedToTrash);
             },
             onError: (e, s) {
-              showGenericErrorDialog(context: context);
+              showGenericErrorDialog(context: context, error: e);
             },
           );
         },
@@ -620,7 +626,7 @@ Future<void> showDeleteSheet(
   );
   if (actionResult?.action != null &&
       actionResult!.action == ButtonAction.error) {
-    showGenericErrorDialog(context: context);
+    showGenericErrorDialog(context: context, error: actionResult.exception);
   } else {
     selectedFiles.clearAll();
   }

+ 76 - 5
lib/utils/dialog_util.dart

@@ -1,6 +1,8 @@
 import "package:dio/dio.dart";
+import "package:flutter/foundation.dart";
 import 'package:flutter/material.dart';
 import "package:flutter/services.dart";
+import "package:photos/core/constants.dart";
 import "package:photos/generated/l10n.dart";
 import 'package:photos/models/button_result.dart';
 import 'package:photos/models/typedefs.dart';
@@ -11,6 +13,7 @@ import 'package:photos/ui/components/action_sheet_widget.dart';
 import 'package:photos/ui/components/buttons/button_widget.dart';
 import 'package:photos/ui/components/dialog_widget.dart';
 import 'package:photos/ui/components/models/button_type.dart';
+import "package:photos/utils/email_util.dart";
 
 typedef DialogBuilder = DialogWidget Function(BuildContext context);
 
@@ -68,25 +71,93 @@ Future<ButtonResult?> showErrorDialogForException({
   );
 }
 
+String parseErrorForUI(
+  BuildContext context,
+  String genericError, {
+  Object? error,
+  bool surfaceError = kDebugMode,
+}) {
+  if (error == null) {
+    return genericError;
+  }
+  if (error is DioError) {
+    final DioError dioError = error;
+    if (dioError.type == DioErrorType.other) {
+      if (dioError.error.toString().contains('Failed host lookup')) {
+        return S.of(context).networkHostLookUpErr;
+      } else if (dioError.error.toString().contains('SocketException')) {
+        return S.of(context).networkConnectionRefusedErr;
+      }
+    }
+  }
+  // return generic error if the user is not internal and the error is not in debug mode
+  if (!(isInternalUser && kDebugMode)) {
+    return genericError;
+  }
+  String errorInfo = "";
+  if (error is DioError) {
+    final DioError dioError = error;
+    if (dioError.type == DioErrorType.response) {
+      if (dioError.response?.data["code"] != null) {
+        errorInfo = "Reason: " + dioError.response!.data["code"];
+      } else {
+        errorInfo = "Reason: " + dioError.response!.data.toString();
+      }
+    } else if (dioError.type == DioErrorType.other) {
+      errorInfo = "Reason: " + dioError.error.toString();
+    } else {
+      errorInfo = "Reason: " + dioError.type.toString();
+    }
+  } else {
+    errorInfo = error.toString().split('Source stack')[0];
+  }
+  if (errorInfo.isNotEmpty) {
+    return "$genericError\n\n$errorInfo";
+  }
+  return genericError;
+}
+
 ///Will return null if dismissed by tapping outside
 Future<ButtonResult?> showGenericErrorDialog({
   required BuildContext context,
   bool isDismissible = true,
+  required Object? error,
 }) async {
-  return showDialogWidget(
+  final errorBody = parseErrorForUI(
+    context,
+    S.of(context).itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
+    error: error,
+  );
+
+  final ButtonResult? result = await showDialogWidget(
     context: context,
     title: S.of(context).error,
     icon: Icons.error_outline_outlined,
-    body: S.of(context).itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
+    body: errorBody,
     isDismissible: isDismissible,
-    buttons: const [
+    buttons: [
       ButtonWidget(
-        buttonType: ButtonType.secondary,
-        labelText: "OK",
+        buttonType: ButtonType.primary,
+        labelText: S.of(context).ok,
+        buttonAction: ButtonAction.first,
         isInAlert: true,
       ),
+      ButtonWidget(
+        buttonType: ButtonType.secondary,
+        labelText: S.of(context).contactSupport,
+        buttonAction: ButtonAction.second,
+        onTap: () async {
+          await sendLogs(
+            context,
+            S.of(context).contactSupport,
+            "support@ente.io",
+            postShare: () {},
+          );
+        },
+      ),
     ],
   );
+  return result;
 }
 
 DialogWidget choiceDialog({

+ 1 - 1
lib/utils/magic_util.dart

@@ -218,7 +218,7 @@ Future<void> editFilename(
   );
   if (result is Exception) {
     _logger.severe("Failed to rename file");
-    showGenericErrorDialog(context: context);
+    showGenericErrorDialog(context: context, error: result);
   }
 }
 

+ 1 - 1
lib/utils/share_util.dart

@@ -74,7 +74,7 @@ Future<void> share(
       s,
     );
     await dialog.hide();
-    await showGenericErrorDialog(context: context);
+    await showGenericErrorDialog(context: context, error: e);
   }
 }
 

+ 1 - 1
pubspec.yaml

@@ -12,7 +12,7 @@ description: ente photos application
 # Read more about iOS versioning at
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 
-version: 0.8.4+524
+version: 0.8.5+525
 
 environment:
   sdk: ">=3.0.0 <4.0.0"