From b6e781fa245328636fad73d730cd651fe1d49a3b Mon Sep 17 00:00:00 2001 From: Harry <109690906+harry-signal@users.noreply.github.com> Date: Fri, 24 Mar 2023 13:51:05 -0700 Subject: [PATCH] Allow switching to secondary device linking from new registration and vice versa * add copy pasted RegistrationConfirmModeSwitchViewController * enable switching registration and secondary device linking back and forth --- Signal.xcodeproj/project.pbxproj | 4 + .../RegistrationCoordinator.swift | 6 ++ .../RegistrationCoordinatorImpl.swift | 15 ++++ .../RegistrationNavigationController.swift | 16 ++++ .../Deprecated_OnboardingController.swift | 8 ++ ...ModeSwitchConfirmationViewController.swift | 2 +- ...cated_OnboardingSplashViewController.swift | 14 ++- ...ationConfirmModeSwitchViewController.swift | 90 +++++++++++++++++++ .../RegistrationLoadingViewController.swift | 4 +- .../RegistrationSplashViewController.swift | 5 +- Signal/src/environment/SignalApp.swift | 41 +++++---- 11 files changed, 180 insertions(+), 25 deletions(-) create mode 100644 Signal/src/ViewControllers/Registration/RegistrationConfirmModeSwitchViewController.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index cd75172158..d093da4c73 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -836,6 +836,7 @@ 66586D3829005A1B00DDA9B9 /* story_viewer_onboarding_1.json in Resources */ = {isa = PBXBuildFile; fileRef = 66586D3529005A1B00DDA9B9 /* story_viewer_onboarding_1.json */; }; 66586D3929005A1B00DDA9B9 /* story_viewer_onboarding_3.json in Resources */ = {isa = PBXBuildFile; fileRef = 66586D3629005A1B00DDA9B9 /* story_viewer_onboarding_3.json */; }; 66586D4129009C0000DDA9B9 /* TextAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66586D4029009C0000DDA9B9 /* TextAttachment.swift */; }; + 6659CCB129CD4650000C24C0 /* RegistrationConfirmModeSwitchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6659CCB029CD4650000C24C0 /* RegistrationConfirmModeSwitchViewController.swift */; }; 665EF86D290C385B00F490D2 /* OWSNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 665EF86C290C385B00F490D2 /* OWSNavigationController.swift */; }; 6673FF702978C40300F96CFD /* KBSAuthCredentialStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6673FF6F2978C40300F96CFD /* KBSAuthCredentialStorage.swift */; }; 6673FF722979B33800F96CFD /* KBSAuthCredentialStorageImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6673FF712979B33800F96CFD /* KBSAuthCredentialStorageImpl.swift */; }; @@ -3302,6 +3303,7 @@ 66586D3529005A1B00DDA9B9 /* story_viewer_onboarding_1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = story_viewer_onboarding_1.json; sourceTree = ""; }; 66586D3629005A1B00DDA9B9 /* story_viewer_onboarding_3.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = story_viewer_onboarding_3.json; sourceTree = ""; }; 66586D4029009C0000DDA9B9 /* TextAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttachment.swift; sourceTree = ""; }; + 6659CCB029CD4650000C24C0 /* RegistrationConfirmModeSwitchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationConfirmModeSwitchViewController.swift; sourceTree = ""; }; 665EF86C290C385B00F490D2 /* OWSNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSNavigationController.swift; sourceTree = ""; }; 6673FF6F2978C40300F96CFD /* KBSAuthCredentialStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KBSAuthCredentialStorage.swift; sourceTree = ""; }; 6673FF712979B33800F96CFD /* KBSAuthCredentialStorageImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KBSAuthCredentialStorageImpl.swift; sourceTree = ""; }; @@ -5037,6 +5039,7 @@ 66AAC2C329CB6F1100566AD6 /* RegistrationChangeNumberSplashViewController.swift */, 66AAC2C729CB9ED900566AD6 /* RegistrationChangePhoneNumberConfirmationViewController.swift */, 66AAC2C529CB942F00566AD6 /* RegistrationChangePhoneNumberViewController.swift */, + 6659CCB029CD4650000C24C0 /* RegistrationConfirmModeSwitchViewController.swift */, F92E4C73299E9A0100C6E6C7 /* RegistrationLoadingViewController.swift */, F9D5C39E2993F9FF004891FC /* RegistrationPermissionsViewController.swift */, F905DFEA29A534F200BAD034 /* RegistrationPhoneNumberDiscoverabilityViewController.swift */, @@ -11387,6 +11390,7 @@ 66AAC2C429CB6F1100566AD6 /* RegistrationChangeNumberSplashViewController.swift in Sources */, 66AAC2C829CB9ED900566AD6 /* RegistrationChangePhoneNumberConfirmationViewController.swift in Sources */, 66AAC2C629CB942F00566AD6 /* RegistrationChangePhoneNumberViewController.swift in Sources */, + 6659CCB129CD4650000C24C0 /* RegistrationConfirmModeSwitchViewController.swift in Sources */, 6600F39629919ECC00B1EDB7 /* RegistrationCoodinatorShims.swift in Sources */, 66E3C8F62994634E00BB38ED /* RegistrationCoordinator.swift in Sources */, 66F0F1DF29C12363008C0ECE /* RegistrationCoordinatorDependencies.swift in Sources */, diff --git a/Signal/Registration/RegistrationCoordinator.swift b/Signal/Registration/RegistrationCoordinator.swift index 6f70a4f44d..a8b0d406b4 100644 --- a/Signal/Registration/RegistrationCoordinator.swift +++ b/Signal/Registration/RegistrationCoordinator.swift @@ -9,6 +9,12 @@ import Foundation /// including re-registration and change number. public protocol RegistrationCoordinator { + /// Prepare to switch to secondary device linking, if allowed. + /// If this returns true, state will have been appropriately cleared + /// in order to proceed to seconday device linking; if not the + /// user/device is not allowed and should stay in primary registration. + func switchToSecondaryDeviceLinking() -> Bool + /// Attempt to exit registration, returning true if allowed. /// /// When allowed differs by `RegistrationMode`: diff --git a/Signal/Registration/RegistrationCoordinatorImpl.swift b/Signal/Registration/RegistrationCoordinatorImpl.swift index f0e8fc8791..f78e1637d4 100644 --- a/Signal/Registration/RegistrationCoordinatorImpl.swift +++ b/Signal/Registration/RegistrationCoordinatorImpl.swift @@ -33,6 +33,21 @@ public class RegistrationCoordinatorImpl: RegistrationCoordinator { // MARK: - Public API + public func switchToSecondaryDeviceLinking() -> Bool { + switch mode { + case .registering: + if persistedState.hasShownSplash { + // Once we are past the splash, no going back. + return false + } else { + self.wipePersistedState() + return true + } + case .reRegistering, .changingNumber: + return false + } + } + public func exitRegistration() -> Bool { guard canExitRegistrationFlow() else { return false diff --git a/Signal/Registration/ViewControllers/RegistrationNavigationController.swift b/Signal/Registration/ViewControllers/RegistrationNavigationController.swift index ee3a536ba3..e19a4d3a6f 100644 --- a/Signal/Registration/ViewControllers/RegistrationNavigationController.swift +++ b/Signal/Registration/ViewControllers/RegistrationNavigationController.swift @@ -326,6 +326,22 @@ extension RegistrationNavigationController: RegistrationSplashPresenter { public func continueFromSplash() { pushNextController(coordinator.continueFromSplash()) } + + public func switchToDeviceLinkingMode() { + let controller = RegistrationConfirmModeSwitchViewController(presenter: self) + pushViewController(controller, animated: true, completion: nil) + } +} + +extension RegistrationNavigationController: RegistrationConfimModeSwitchPresenter { + + public func confirmSwitchToDeviceLinkingMode() { + guard coordinator.switchToSecondaryDeviceLinking() else { + owsFailBeta("Can't switch to secondary device linking") + return + } + SignalApp.shared().showDeprecatedOnboardingView(.init(context: .shared, onboardingMode: .provisioning)) + } } extension RegistrationNavigationController: RegistrationChangeNumberSplashPresenter {} diff --git a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingController.swift b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingController.swift index d7f9212ac2..f78bb08fba 100644 --- a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingController.swift +++ b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingController.swift @@ -33,6 +33,8 @@ public class Deprecated_OnboardingNavigationController: OWSNavigationController // MARK: - +// TODO[Registration]: pull out the parts of this related to secondary device +// linking into simpler classes and delete the rest once once new registration rolls out. @objc public class Deprecated_OnboardingController: NSObject { @@ -218,6 +220,12 @@ public class Deprecated_OnboardingController: NSObject { Logger.info("") + if FeatureFlags.useNewRegistrationFlow, onboardingMode == .provisioning { + let loader = RegistrationCoordinatorLoaderImpl(dependencies: .from(self)) + signalApp.showRegistration(loader: loader, desiredMode: .registering) + return + } + switch Self.defaultOnboardingMode { case .registering: onboardingMode = .provisioning diff --git a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingModeSwitchConfirmationViewController.swift b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingModeSwitchConfirmationViewController.swift index 055665fdc5..6725ea3043 100644 --- a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingModeSwitchConfirmationViewController.swift +++ b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingModeSwitchConfirmationViewController.swift @@ -21,7 +21,7 @@ class Deprecated_OnboardingModeSwitchConfirmationViewController: Deprecated_Onbo let nextButtonText: String let image: UIImage? - switch Deprecated_OnboardingController.defaultOnboardingMode { + switch onboardingController.onboardingMode { case .registering: titleText = NSLocalizedString("ONBOARDING_MODE_SWITCH_TITLE_REGISTERING", comment: "header text indicating to the user they're switching from registering to linking flow") diff --git a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingSplashViewController.swift b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingSplashViewController.swift index 2bc4e98ce3..5c35771165 100644 --- a/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingSplashViewController.swift +++ b/Signal/src/ViewControllers/Registration/Onboarding/Deprecated_OnboardingSplashViewController.swift @@ -94,10 +94,16 @@ public class Deprecated_OnboardingSplashViewController: Deprecated_OnboardingBas override public func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - // Whenever this view appears, we should switch back to the default - // registration mode. If the user wants to use the other one, they need to - // tap the link icon and confirm their selection. - onboardingController.onboardingMode = Deprecated_OnboardingController.defaultOnboardingMode + if !FeatureFlags.useNewRegistrationFlow { + // Whenever this view appears, we should switch back to the default + // registration mode. If the user wants to use the other one, they need to + // tap the link icon and confirm their selection. + onboardingController.onboardingMode = Deprecated_OnboardingController.defaultOnboardingMode + } + } + + override func shouldShowBackButton() -> Bool { + return false } // MARK: - Events diff --git a/Signal/src/ViewControllers/Registration/RegistrationConfirmModeSwitchViewController.swift b/Signal/src/ViewControllers/Registration/RegistrationConfirmModeSwitchViewController.swift new file mode 100644 index 0000000000..f40851a208 --- /dev/null +++ b/Signal/src/ViewControllers/Registration/RegistrationConfirmModeSwitchViewController.swift @@ -0,0 +1,90 @@ +// +// Copyright 2023 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +// + +import Foundation +import SignalMessaging +import SignalUI + +protocol RegistrationConfimModeSwitchPresenter: AnyObject { + + func confirmSwitchToDeviceLinkingMode() +} + +class RegistrationConfirmModeSwitchViewController: OWSViewController { + var warningText: String? + + weak var presenter: RegistrationConfimModeSwitchPresenter? + + public init(presenter: RegistrationConfimModeSwitchPresenter) { + self.presenter = presenter + super.init() + } + + override func loadView() { + view = UIView() + + view.backgroundColor = Theme.backgroundColor + + let titleText = NSLocalizedString("ONBOARDING_MODE_SWITCH_TITLE_REGISTERING", + comment: "header text indicating to the user they're switching from registering to linking flow") + let explanationText = NSLocalizedString("ONBOARDING_MODE_SWITCH_EXPLANATION_REGISTERING", + comment: "explanation to the user they're switching from registering to linking flow") + + let nextButtonText = NSLocalizedString("ONBOARDING_MODE_SWITCH_BUTTON_REGISTERING", + comment: "button indicating that the user will link their phone") + + warningText = NSLocalizedString("ONBOARDING_MODE_SWITCH_WARNING_REGISTERING", + comment: "warning to the user that linking a phone is not recommended") + + let titleLabel = UILabel.titleLabelForRegistration(text: titleText) + + let explanationLabel = UILabel.explanationLabelForRegistration(text: explanationText) + + let nextButton = OWSFlatButton.primaryButtonForRegistration( + title: nextButtonText, + target: self, + selector: #selector(didPressNext) + ) + nextButton.accessibilityIdentifier = "onboarding.modeSwitch.nextButton" + let primaryButtonView = Deprecated_OnboardingBaseViewController.horizontallyWrap(primaryButton: nextButton) + + let topSpacer = UIView.vStretchingSpacer(minHeight: 12) + let bottomSpacer = UIView.vStretchingSpacer(minHeight: 12) + + let stackView = UIStackView(arrangedSubviews: [ + titleLabel, + UIView.spacer(withHeight: 12), + explanationLabel, + topSpacer, + bottomSpacer, + primaryButtonView + ]) + stackView.axis = .vertical + stackView.alignment = .fill + stackView.spacing = 12 + view.addSubview(stackView) + + topSpacer.autoMatch(.height, to: .height, of: bottomSpacer) + + stackView.autoPinEdgesToSuperviewMargins() + } + + @objc + func didPressNext() { + let actionSheet = ActionSheetController(message: warningText) + + let continueAction = ActionSheetAction( + title: CommonStrings.continueButton, + accessibilityIdentifier: "onboarding.modeSwitch.continue", + handler: { [weak self] _ in + self?.presenter?.confirmSwitchToDeviceLinkingMode() + } + ) + actionSheet.addAction(continueAction) + actionSheet.addAction(OWSActionSheets.cancelAction) + + presentActionSheet(actionSheet) + } +} diff --git a/Signal/src/ViewControllers/Registration/RegistrationLoadingViewController.swift b/Signal/src/ViewControllers/Registration/RegistrationLoadingViewController.swift index b4a70d9257..47469a6ec1 100644 --- a/Signal/src/ViewControllers/Registration/RegistrationLoadingViewController.swift +++ b/Signal/src/ViewControllers/Registration/RegistrationLoadingViewController.swift @@ -50,7 +50,9 @@ class RegistrationLoadingViewController: OWSViewController { public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - spinnerView.startAnimating() + if spinnerView.isAnimating.negated { + spinnerView.startAnimating() + } } public override func themeDidChange() { diff --git a/Signal/src/ViewControllers/Registration/RegistrationSplashViewController.swift b/Signal/src/ViewControllers/Registration/RegistrationSplashViewController.swift index dd56ce7d84..31898a9a18 100644 --- a/Signal/src/ViewControllers/Registration/RegistrationSplashViewController.swift +++ b/Signal/src/ViewControllers/Registration/RegistrationSplashViewController.swift @@ -12,6 +12,8 @@ import SignalMessaging public protocol RegistrationSplashPresenter: AnyObject { func continueFromSplash() + + func switchToDeviceLinkingMode() } // MARK: - RegistrationSplashViewController @@ -126,7 +128,8 @@ public class RegistrationSplashViewController: OWSViewController { @objc private func didTapModeSwitch() { Logger.info("") - owsFail("TODO[Registration] Not implemented") + + presenter?.switchToDeviceLinkingMode() } @objc diff --git a/Signal/src/environment/SignalApp.swift b/Signal/src/environment/SignalApp.swift index 9bfb5d58b6..c91609c271 100644 --- a/Signal/src/environment/SignalApp.swift +++ b/Signal/src/environment/SignalApp.swift @@ -59,25 +59,20 @@ extension SignalApp { let onboardingController = Deprecated_OnboardingController() if FeatureFlags.useNewRegistrationFlow { - var desiredMode: RegistrationMode? = DependenciesBridge.shared.db.read { + if let lastMode = DependenciesBridge.shared.db.read(block: { return registrationLoader.restoreLastMode(transaction: $0) - } - if desiredMode == nil { - // Check for legacy state. - // TODO[Registration]: use a db migration to move this state to reg coordinator. - if !onboardingController.isComplete { - desiredMode = .registering + }) { + showRegistration(loader: registrationLoader, desiredMode: lastMode) + AppReadiness.setUIIsReady() + // TODO[Registration]: use a db migration to move isComplete state to reg coordinator. + } else if !onboardingController.isComplete { + if UIDevice.current.isIPad { + showDeprecatedOnboardingView(onboardingController) + AppReadiness.setUIIsReady() + } else { + showRegistration(loader: registrationLoader, desiredMode: .registering) + AppReadiness.setUIIsReady() } - } - if let desiredMode { - let coordinator = databaseStorage.write { tx in - return registrationLoader.coordinator(forDesiredMode: desiredMode, transaction: tx.asV2Write) - } - let navController = RegistrationNavigationController.withCoordinator(coordinator) - - appDelegate.window??.rootViewController = navController - - conversationSplitViewController = nil } else { onboardingController.markAsOnboarded() showConversationSplitView() @@ -88,7 +83,6 @@ extension SignalApp { showConversationSplitView() } else { showDeprecatedOnboardingView(onboardingController) - AppReadiness.setUIIsReady() } } @@ -104,6 +98,17 @@ extension SignalApp { } conversationSplitViewController.showAppSettingsWithMode(mode) } + + func showRegistration(loader: RegistrationCoordinatorLoader, desiredMode: RegistrationMode) { + let coordinator = databaseStorage.write { tx in + return loader.coordinator(forDesiredMode: desiredMode, transaction: tx.asV2Write) + } + let navController = RegistrationNavigationController.withCoordinator(coordinator) + + UIApplication.shared.delegate?.window??.rootViewController = navController + + conversationSplitViewController = nil + } } extension SignalApp {