// // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public enum RegistrationStep: Equatable { // MARK: - Opening Steps case registrationSplash case changeNumberSplash case permissions(RegistrationPermissionsState) // MARK: - Actually registering /// The user should enter or confirm their phone number. /// The number may be pre-filled or empty; either way we will require /// the user to confirm the number at least once before proceeding. /// The number may be used to send an SMS or as a way to identify the /// account being registered for via KBS backup info. case phoneNumberEntry(RegistrationPhoneNumberViewState) /// If registering via session, the step to enter the verification code. case verificationCodeEntry(RegistrationVerificationState) /// When registering, the server can inform the client that a device-to-device /// transfer is possible. If so, the user must either do the transfer, or explicitly /// elect not to. This step presents those options to the user. /// Only happens if registering on a new device without local data. case transferSelection /// For the first time we enter the pin. This can be /// for first account setup, creating a pin, or if /// re-registering and needing to confirm the pin. /// When doing first time setup, the pin must be confirmed; that is /// considered part of this same "step" and is just a UI detail. case pinEntry(RegistrationPinState) /// All PIN attempts have been exhausted. The user may still be able to register, /// but they cannot recover their kbs backups. case pinAttemptsExhaustedWithoutReglock(RegistrationPinAttemptsExhaustedViewState) /// At _any_ point during session-based registration, a captcha challenge may be /// requested. case captchaChallenge /// If we encounter reglock, fail to recover the kbs backups (probably because /// PIN guesses got used up), we have no choice but to wait out the reglock. case reglockTimeout(RegistrationReglockTimeoutState) // MARK: - Post-Registration /// If the user has successfully recovered their master key and can attempt to /// restore from a local message backup. case restoreFromLocalMessageBackup /// If the account has not set whether its phone number should be /// discoverable, this step happens after registration is complete. /// (Typically skipped during re-registration as a result.) case phoneNumberDiscoverability(RegistrationPhoneNumberDiscoverabilityState) /// If the account has not set profile info, this step happens after registration is complete. /// (Typically skipped during re-registration as a result.) case setupProfile(RegistrationProfileState) // MARK: - Non-ViewController steps public enum ErrorSheet: Equatable { /// We should tell the user their attempt has expired /// and they need to start over. case sessionInvalidated /// The user can no longer submit a verification code. /// This could be because the previously sent code expired, /// or because they used up their verification code attempts. /// In either case, they need to send a new code to proceed. case verificationCodeSubmissionUnavailable /// The user tried to submit a verification code, but we've never /// actually sent a code, so no submission could possibly be correct. case submittingVerificationCodeBeforeAnyCodeSent /// The user had completed registration, but before finishing /// post-registration steps they were deregistered, likely by /// another device registering on the same number. /// The only path forward is to reset _everything_ and re-register. case becameDeregistered(reregParams: RegistrationMode.ReregistrationParams) /// A network error occurred. The user can probably fix this by /// checking their internet connection. case networkError /// A generic error occurred. Prefer to use other error types. case genericError } /// Special cases; should display an error on the current screen, whatever it is. /// (If this is returned as the first step, show the splash and then this error). /// This sheet should be undismissable; the user must ack it to proceed, and doing /// so should call `RegistrationCoordinator.nextStep()` case showErrorSheet(ErrorSheet) /// Special case, should display a banner on the current screen, whatever it is. /// Happens if we get a response from the server we can't parse; we assume this means /// an app version update is needed to parse it. /// (If this is returned as the first step, show the splash and then this error). case appUpdateBanner /// Special case; done with the registration flow! case done // MARK: - Logging public var logSafeString: String { switch self { case .registrationSplash: return "registrationSplash" case .changeNumberSplash: return "changeNumberSplash" case .permissions: return "permissions" case .phoneNumberEntry: return "phoneNumberEntry" case .verificationCodeEntry: return "verificationCodeEntry" case .transferSelection: return "transferSelection" case .pinEntry: return "pinEntry" case .pinAttemptsExhaustedWithoutReglock: return "pinAttemptsExhaustedWithoutReglock" case .captchaChallenge: return "captchaChallenge" case .reglockTimeout: return "reglockTimeout" case .restoreFromLocalMessageBackup: return "restoreFromLocalMessageBackup" case .phoneNumberDiscoverability: return "phoneNumberDiscoverability" case .setupProfile: return "setupProfile" case .showErrorSheet: return "showErrorSheet" case .appUpdateBanner: return "appUpdateBanner" case .done: return "done" } } }