From dcf02125a01d6849fd1e1c75e8d089bf5fd951f8 Mon Sep 17 00:00:00 2001 From: Sasha Weiss Date: Mon, 1 Jun 2026 11:04:13 -0700 Subject: [PATCH] Simplify PIN creation error handling --- .../UserInterface/IntroducingPINs.swift | 23 +++-- .../AccountSettingsViewController.swift | 4 +- ...vancedPinSettingsTableViewController.swift | 2 +- .../PinReminderViewController.swift | 5 +- .../PinSetupViewController.swift | 83 +++++-------------- .../translations/en.lproj/Localizable.strings | 22 ++--- 6 files changed, 43 insertions(+), 96 deletions(-) diff --git a/Signal/Megaphones/UserInterface/IntroducingPINs.swift b/Signal/Megaphones/UserInterface/IntroducingPINs.swift index 991475b7f0..410ab1372e 100644 --- a/Signal/Megaphones/UserInterface/IntroducingPINs.swift +++ b/Signal/Megaphones/UserInterface/IntroducingPINs.swift @@ -21,18 +21,17 @@ class IntroducingPinsMegaphone: MegaphoneView { let viewController = PinSetupViewController( mode: .creating, showCancelButton: true, - completionHandler: { [weak self, weak fromViewController] _, error in - guard let self, let fromViewController else { return } - if let error { - Logger.error("failed to create pin: \(error)") - } else { - // success - self.markAsCompleteWithSneakyTransaction() - } - self.dismiss(animated: false) - fromViewController.dismiss(animated: true) { - self.presentToast( - text: OWSLocalizedString("PINS_MEGAPHONE_TOAST", comment: "Toast indicating that a PIN has been created."), + onSuccess: { pinSetupViewController in + pinSetupViewController.dismiss(animated: true) { [weak self, weak fromViewController] in + guard let self, let fromViewController else { return } + + markAsCompleteWithSneakyTransaction() + + presentToast( + text: OWSLocalizedString( + "PINS_MEGAPHONE_TOAST", + comment: "Toast indicating that a PIN has been created.", + ), fromViewController: fromViewController, ) } diff --git a/Signal/src/ViewControllers/AppSettings/Account/AccountSettingsViewController.swift b/Signal/src/ViewControllers/AppSettings/Account/AccountSettingsViewController.swift index 9cd0cf56b1..6f95a5aa40 100644 --- a/Signal/src/ViewControllers/AppSettings/Account/AccountSettingsViewController.swift +++ b/Signal/src/ViewControllers/AppSettings/Account/AccountSettingsViewController.swift @@ -498,7 +498,7 @@ class AccountSettingsViewController: OWSTableViewController2 { // MARK: - private func showChangePin() { - let vc = PinSetupViewController(mode: .changing) { [weak self] _, _ in + let vc = PinSetupViewController(mode: .changing) { [weak self] _ in guard let self else { return } self.navigationController?.popToViewController(self, animated: true) } @@ -508,7 +508,7 @@ class AccountSettingsViewController: OWSTableViewController2 { private func showCreatePin() { let vc = PinSetupViewController( mode: .creating, - ) { [weak self] _, _ in + ) { [weak self] _ in guard let self else { return } self.navigationController?.popToViewController(self, animated: true) } diff --git a/Signal/src/ViewControllers/AppSettings/Account/AdvancedPinSettingsTableViewController.swift b/Signal/src/ViewControllers/AppSettings/Account/AdvancedPinSettingsTableViewController.swift index fc6c1ef01c..b9caacd9d5 100644 --- a/Signal/src/ViewControllers/AppSettings/Account/AdvancedPinSettingsTableViewController.swift +++ b/Signal/src/ViewControllers/AppSettings/Account/AdvancedPinSettingsTableViewController.swift @@ -113,7 +113,7 @@ class AdvancedPinSettingsTableViewController: OWSTableViewController2 { private func showCreatePin() { let viewController = PinSetupViewController( mode: .creating, - completionHandler: { [weak self] _, _ in + onSuccess: { [weak self] _ in guard let self else { return } self.navigationController?.popToViewController(self, animated: true) self.updateTableContents() diff --git a/Signal/src/ViewControllers/PinReminderViewController.swift b/Signal/src/ViewControllers/PinReminderViewController.swift index 5fce66c042..ce16cc80e7 100644 --- a/Signal/src/ViewControllers/PinReminderViewController.swift +++ b/Signal/src/ViewControllers/PinReminderViewController.swift @@ -339,7 +339,10 @@ public class PinReminderViewController: OWSViewController { let viewController = PinSetupViewController( mode: .creating, showCancelButton: true, - completionHandler: { [weak self] _, _ in self?.completionHandler?(.changedPin) }, + onSuccess: { [weak self] _ in + guard let self else { return } + completionHandler?(.changedPin) + }, ) present(OWSNavigationController(rootViewController: viewController), animated: true) } diff --git a/Signal/src/ViewControllers/PinSetupViewController.swift b/Signal/src/ViewControllers/PinSetupViewController.swift index 4028990dfd..e7bceeffb4 100644 --- a/Signal/src/ViewControllers/PinSetupViewController.swift +++ b/Signal/src/ViewControllers/PinSetupViewController.swift @@ -180,22 +180,20 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro private let showCancelButton: Bool - // Called once pin setup has finished. Error will be nil upon success - private let completionHandler: (PinSetupViewController, Error?) -> Void - + private let onSuccess: (PinSetupViewController) -> Void private let context: ViewControllerContext convenience init( mode: Mode, showCancelButton: Bool = false, - completionHandler: @escaping (PinSetupViewController, Error?) -> Void, + onSuccess: @escaping (PinSetupViewController) -> Void, ) { self.init( mode: mode, initialMode: mode, pinType: .numeric, showCancelButton: showCancelButton, - completionHandler: completionHandler, + onSuccess: onSuccess, ) } @@ -204,14 +202,14 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro initialMode: Mode, pinType: OWS2FAManager.PinType, showCancelButton: Bool, - completionHandler: @escaping (PinSetupViewController, Error?) -> Void, + onSuccess: @escaping (PinSetupViewController) -> Void, ) { assert(DependenciesBridge.shared.tsAccountManager.registrationStateWithMaybeSneakyTransaction.isRegisteredPrimaryDevice) self.mode = mode self.initialMode = initialMode self.pinType = pinType self.showCancelButton = showCancelButton - self.completionHandler = completionHandler + self.onSuccess = onSuccess // TODO[ViewContextPiping] self.context = ViewControllerContext.shared super.init() @@ -339,7 +337,7 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro initialMode: initialMode, pinType: pinType, showCancelButton: false, // we're pushing, so we never need a cancel button - completionHandler: completionHandler, + onSuccess: onSuccess, ) navigationController?.pushViewController(confirmingVC, animated: true) case .confirming: @@ -436,11 +434,6 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro } } - private enum PinSetupError: Error { - case networkFailure - case enable2FA - } - private func enable2FAAndContinue(withPin pin: String) { Logger.debug("") @@ -474,7 +467,7 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro DispatchQueue.main.async { // The completion handler always dismisses this view, so we don't want to animate anything. progressView.stopAnimatingImmediately() - self.completionHandler(self, nil) + self.onSuccess(self) } } catch { DispatchQueue.main.async { @@ -487,53 +480,22 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro self.view.isUserInteractionEnabled = true progressView.removeFromSuperview() - guard let error = error as? PinSetupError else { - return owsFailDebug("Unexpected error during PIN setup \(error)") - } - - switch error { - case .networkFailure: + if error.isNetworkFailureOrTimeout { OWSActionSheets.showActionSheet( - title: OWSLocalizedString( - "PIN_CREATION_NO_NETWORK_ERROR_TITLE", - comment: "Error title indicating that the attempt to create a PIN failed due to network issues.", - ), message: OWSLocalizedString( - "PIN_CREATION_NO_NETWORK_ERROR_MESSAGE", - comment: "Error body indicating that the attempt to create a PIN failed due to network issues.", + "PIN_CREATION_NETWORK_ERROR_MESSAGE", + comment: "Message when a network error occurs while creating a PIN.", ), ) - case .enable2FA: - switch self.initialMode { - case .changing: - OWSActionSheets.showActionSheet( - title: OWSLocalizedString( - "PIN_CHANGE_ERROR_TITLE", - comment: "Error title indicating that the attempt to change a PIN failed.", - ), - message: OWSLocalizedString( - "PIN_CHANGE_ERROR_MESSAGE", - comment: "Error body indicating that the attempt to change a PIN failed.", - ), - ) { _ in - self.completionHandler(self, error) - } - case .creating: - OWSActionSheets.showActionSheet( - title: OWSLocalizedString( - "PIN_RECREATION_ERROR_TITLE", - comment: "Error title indicating that the attempt to recreate a PIN failed.", - ), - message: OWSLocalizedString( - "PIN_RECRETION_ERROR_MESSAGE", - comment: "Error body indicating that the attempt to recreate a PIN failed.", - ), - ) { _ in - self.completionHandler(self, error) - } - case .confirming: - owsFailDebug("Unexpected initial mode") - } + } else { + OWSActionSheets.showContactSupportActionSheet( + message: OWSLocalizedString( + "PIN_CREATION_GENERIC_ERROR_MESSAGE", + comment: "Message when a generic error occurs while creating a PIN.", + ), + emailFilter: .custom("PinCreateFailure"), + fromViewController: self, + ) } } } @@ -551,12 +513,7 @@ public class PinSetupViewController: OWSViewController, OWSNavigationChildContro try await ows2FAManager.enablePin(pin) } catch { owsFailDebug("Failed to set PIN! \(error)") - - if error.isNetworkFailureOrTimeout { - throw PinSetupError.networkFailure - } - - throw PinSetupError.enable2FA + throw error } await DependenciesBridge.shared.db.awaitableWrite { tx in diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 1ed9302247..fee4de1658 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -6808,12 +6808,6 @@ /* Pressing this button pins a thread */ "PIN_ACTION" = "Pin"; -/* Error body indicating that the attempt to change a PIN failed. */ -"PIN_CHANGE_ERROR_MESSAGE" = "Couldn't create your new PIN. Your existing PIN has been disabled. Check your connection and try again."; - -/* Error title indicating that the attempt to change a PIN failed. */ -"PIN_CHANGE_ERROR_TITLE" = "PIN Change Failed"; - /* Label indicating the user must use at least 4 characters */ "PIN_CREATION_ALPHANUMERIC_HINT" = "PIN must be at least 4 characters"; @@ -6844,6 +6838,9 @@ /* The explanation in the 'pin creation' view. */ "PIN_CREATION_EXPLANATION" = "PINs keep information stored with Signal encrypted so only you can access it. Your profile, settings, and contacts will restore when you reinstall. You won’t need your PIN to open the app."; +/* Message when a generic error occurs while creating a PIN. */ +"PIN_CREATION_GENERIC_ERROR_MESSAGE" = "Something went wrong creating your PIN. Please contact support."; + /* Learn more action on the pin creation view */ "PIN_CREATION_LEARN_MORE" = "More About PINs"; @@ -6856,11 +6853,8 @@ /* Label indicating that the attempted PIN does not match the first PIN */ "PIN_CREATION_MISMATCH_ERROR" = "PINs don’t match. Try again."; -/* Error body indicating that the attempt to create a PIN failed due to network issues. */ -"PIN_CREATION_NO_NETWORK_ERROR_MESSAGE" = "Check your connection and try again."; - -/* Error title indicating that the attempt to create a PIN failed due to network issues. */ -"PIN_CREATION_NO_NETWORK_ERROR_TITLE" = "No Network Connection"; +/* Message when a network error occurs while creating a PIN. */ +"PIN_CREATION_NETWORK_ERROR_MESSAGE" = "Something went wrong creating your PIN. Check your connection and try again."; /* Label indicating the user must use at least 4 digits */ "PIN_CREATION_NUMERIC_HINT" = "PIN must be at least 4 digits"; @@ -6892,12 +6886,6 @@ /* If the user is re-registering, they need to enter their PIN to restore all their data. If they don't remember their PIN, they may remember their Recovery Key which can be used instead of a PIN. */ "PIN_ENTER_EXISTING_USE_RECOVERY_KEY" = "Use Recovery Key"; -/* Error title indicating that the attempt to recreate a PIN failed. */ -"PIN_RECREATION_ERROR_TITLE" = "PIN Creation Failed"; - -/* Error body indicating that the attempt to recreate a PIN failed. */ -"PIN_RECRETION_ERROR_MESSAGE" = "Couldn’t create your PIN. Check your connection and try again."; - /* The explanation for the 'pin reminder' dialog. */ "PIN_REMINDER_EXPLANATION" = "To help you memorize your PIN, we’ll ask you to enter it periodically. We’ll ask less over time.";