diff --git a/Podfile b/Podfile index 51827b099..cf7f831a5 100644 --- a/Podfile +++ b/Podfile @@ -25,7 +25,6 @@ def wordpress_authenticator_pods pod 'Alamofire', '4.8' pod 'CocoaLumberjack', '3.5.2' pod 'GoogleSignIn', '5.0.2' - pod 'lottie-ios', '3.1.6' pod 'NSURL+IDN', '0.4' pod 'SVProgressHUD', '2.2.5' end diff --git a/Podfile.lock b/Podfile.lock index 0016e9d02..50ec7e02b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -26,7 +26,6 @@ PODS: - GTMSessionFetcher/Core (1.4.0) - GTMSessionFetcher/Full (1.4.0): - GTMSessionFetcher/Core (= 1.4.0) - - lottie-ios (3.1.6) - NSObject-SafeExpectations (0.0.4) - "NSURL+IDN (0.4)" - OCMock (3.6) @@ -68,7 +67,6 @@ DEPENDENCIES: - Expecta (= 1.0.6) - GoogleSignIn (= 5.0.2) - Gridicons (~> 1.0-beta) - - lottie-ios (= 3.1.6) - "NSURL+IDN (= 0.4)" - OCMock (~> 3.4) - OHHTTPStubs (= 8.0.0) @@ -91,7 +89,6 @@ SPEC REPOS: - Gridicons - GTMAppAuth - GTMSessionFetcher - - lottie-ios - NSObject-SafeExpectations - "NSURL+IDN" - OCMock @@ -115,7 +112,6 @@ SPEC CHECKSUMS: Gridicons: 8e19276b20bb15d1fda1d4d0db96d066d170135b GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e GTMSessionFetcher: 6f5c8abbab8a9bce4bb3f057e317728ec6182b10 - lottie-ios: 85ce835dd8c53e02509f20729fc7d6a4e6645a0a NSObject-SafeExpectations: ab8fe623d36b25aa1f150affa324e40a2f3c0374 "NSURL+IDN": afc873e639c18138a1589697c3add197fe8679ca OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 @@ -128,6 +124,6 @@ SPEC CHECKSUMS: WordPressUI: 1cf47a3b78154faf69caa18569ee7ece1e510fa0 wpxmlrpc: bf55a43a7e710bd2a4fb8c02dfe83b1246f14f13 -PODFILE CHECKSUM: 02377777b693c2e84274e2a24ccfe6c9d5064b3c +PODFILE CHECKSUM: 1badc6c5b3caef9478b9ea680c1b4e535fc3216e COCOAPODS: 1.10.0 diff --git a/WordPressAuthenticator.xcodeproj/project.pbxproj b/WordPressAuthenticator.xcodeproj/project.pbxproj index 63b61c7d2..3edf6ef3c 100644 --- a/WordPressAuthenticator.xcodeproj/project.pbxproj +++ b/WordPressAuthenticator.xcodeproj/project.pbxproj @@ -96,12 +96,10 @@ B5609139208A563800399AE4 /* LoginEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609128208A563600399AE4 /* LoginEmailViewController.swift */; }; B560913A208A563800399AE4 /* LoginLinkRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609129208A563600399AE4 /* LoginLinkRequestViewController.swift */; }; B560913B208A563800399AE4 /* LoginSelfHostedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560912A208A563600399AE4 /* LoginSelfHostedViewController.swift */; }; - B560913C208A563800399AE4 /* LoginProloguePromoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560912B208A563600399AE4 /* LoginProloguePromoViewController.swift */; }; B560913D208A563800399AE4 /* LoginProloguePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560912C208A563700399AE4 /* LoginProloguePageViewController.swift */; }; B560913E208A563800399AE4 /* SigninEditingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560912D208A563700399AE4 /* SigninEditingState.swift */; }; B560913F208A563800399AE4 /* Login.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B560912E208A563700399AE4 /* Login.storyboard */; }; B5609140208A563800399AE4 /* LoginSocialErrorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560912F208A563700399AE4 /* LoginSocialErrorCell.swift */; }; - B5609141208A563800399AE4 /* LoginPrologueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609130208A563700399AE4 /* LoginPrologueViewController.swift */; }; B5609142208A563800399AE4 /* LoginNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609131208A563700399AE4 /* LoginNavigationController.swift */; }; B5609143208A563800399AE4 /* LoginSocialErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609132208A563700399AE4 /* LoginSocialErrorViewController.swift */; }; B5609144208A563800399AE4 /* LoginPrologueSignupMethodViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5609133208A563700399AE4 /* LoginPrologueSignupMethodViewController.swift */; }; @@ -305,12 +303,10 @@ B5609128208A563600399AE4 /* LoginEmailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginEmailViewController.swift; sourceTree = ""; }; B5609129208A563600399AE4 /* LoginLinkRequestViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginLinkRequestViewController.swift; sourceTree = ""; }; B560912A208A563600399AE4 /* LoginSelfHostedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginSelfHostedViewController.swift; sourceTree = ""; }; - B560912B208A563600399AE4 /* LoginProloguePromoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginProloguePromoViewController.swift; sourceTree = ""; }; B560912C208A563700399AE4 /* LoginProloguePageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginProloguePageViewController.swift; sourceTree = ""; }; B560912D208A563700399AE4 /* SigninEditingState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SigninEditingState.swift; sourceTree = ""; }; B560912E208A563700399AE4 /* Login.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Login.storyboard; sourceTree = ""; }; B560912F208A563700399AE4 /* LoginSocialErrorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginSocialErrorCell.swift; sourceTree = ""; }; - B5609130208A563700399AE4 /* LoginPrologueViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginPrologueViewController.swift; sourceTree = ""; }; B5609131208A563700399AE4 /* LoginNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginNavigationController.swift; sourceTree = ""; }; B5609132208A563700399AE4 /* LoginSocialErrorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginSocialErrorViewController.swift; sourceTree = ""; }; B5609133208A563700399AE4 /* LoginPrologueSignupMethodViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginPrologueSignupMethodViewController.swift; sourceTree = ""; }; @@ -577,9 +573,7 @@ B5609131208A563700399AE4 /* LoginNavigationController.swift */, 982C8E7823021C20003F1BA0 /* LoginPrologueLoginMethodViewController.swift */, B560912C208A563700399AE4 /* LoginProloguePageViewController.swift */, - B560912B208A563600399AE4 /* LoginProloguePromoViewController.swift */, B5609133208A563700399AE4 /* LoginPrologueSignupMethodViewController.swift */, - B5609130208A563700399AE4 /* LoginPrologueViewController.swift */, B560912A208A563600399AE4 /* LoginSelfHostedViewController.swift */, B5609127208A563600399AE4 /* LoginSiteAddressViewController.swift */, B560912F208A563700399AE4 /* LoginSocialErrorCell.swift */, @@ -1191,7 +1185,6 @@ "${BUILT_PRODUCTS_DIR}/WordPressKit/WordPressKit.framework", "${BUILT_PRODUCTS_DIR}/WordPressShared/WordPressShared.framework", "${BUILT_PRODUCTS_DIR}/WordPressUI/WordPressUI.framework", - "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework", "${BUILT_PRODUCTS_DIR}/wpxmlrpc/wpxmlrpc.framework", "${BUILT_PRODUCTS_DIR}/Expecta/Expecta.framework", "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", @@ -1215,7 +1208,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WordPressKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WordPressShared.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WordPressUI.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wpxmlrpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", @@ -1256,7 +1248,6 @@ F1DE08CC24F4266A007AE6B3 /* StoredCredentialsAuthenticator.swift in Sources */, CE1B18CC20EEC32400BECC3F /* WordPressComCredentials.swift in Sources */, 98AA5A5720AA1A7000A5958A /* WPHelpIndicatorView.swift in Sources */, - B560913C208A563800399AE4 /* LoginProloguePromoViewController.swift in Sources */, B560910F208A54F800399AE4 /* SafariCredentialsService.swift in Sources */, B5CDBED420B4714500BC1EF2 /* UIImage+Assets.swift in Sources */, B5609116208A555600399AE4 /* LoginTextField.swift in Sources */, @@ -1313,7 +1304,6 @@ B56090C9208A4F5400399AE4 /* NUXLinkMailViewController.swift in Sources */, B56090F1208A527000399AE4 /* String+Underline.swift in Sources */, B56052A42090B2ED001B91FD /* CircularImageView.swift in Sources */, - B5609141208A563800399AE4 /* LoginPrologueViewController.swift in Sources */, D881A315256B5B5800FE5605 /* NavigateToEnterAccount.swift in Sources */, B56090EB208A51D000399AE4 /* LoginFields.swift in Sources */, B56090FB208A533200399AE4 /* WordPressSupportSourceTag.swift in Sources */, diff --git a/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift b/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift index 98bc20715..a8ef04166 100644 --- a/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift +++ b/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift @@ -110,7 +110,7 @@ import WordPressKit /// Indicates if the specified ViewController belongs to the Authentication Flow, or not. /// public class func isAuthenticationViewController(_ viewController: UIViewController) -> Bool { - return viewController is LoginPrologueViewController || viewController is NUXViewControllerBase + return viewController is NUXViewControllerBase } /// Indicates if the received URL is a Google Authentication Callback. @@ -176,11 +176,7 @@ import WordPressKit assertionFailure("Cannot instantiate initial login controller from Login.storyboard") return nil } - if let childController = controller.children.first as? LoginPrologueViewController { - childController.loginFields.restrictToWPCom = restrictToWPCom - childController.showCancel = showCancel - childController.onLoginButtonTapped = onLoginButtonTapped - } + controller.modalPresentationStyle = .fullScreen return controller } diff --git a/WordPressAuthenticator/Signin/LoginProloguePageViewController.swift b/WordPressAuthenticator/Signin/LoginProloguePageViewController.swift index 5e48708c7..cd427e4d1 100644 --- a/WordPressAuthenticator/Signin/LoginProloguePageViewController.swift +++ b/WordPressAuthenticator/Signin/LoginProloguePageViewController.swift @@ -15,20 +15,6 @@ class LoginProloguePageViewController: UIPageViewController { dataSource = self delegate = self - if WordPressAuthenticator.shared.configuration.enableUnifiedCarousel { - pages.append(LoginProloguePromoViewController(as: .intro)) - pages.append(LoginProloguePromoViewController(as: .editor)) - pages.append(LoginProloguePromoViewController(as: .comments)) - pages.append(LoginProloguePromoViewController(as: .analytics)) - pages.append(LoginProloguePromoViewController(as: .discover)) - } else { - pages.append(LoginProloguePromoViewController(as: .post)) - pages.append(LoginProloguePromoViewController(as: .stats)) - pages.append(LoginProloguePromoViewController(as: .reader)) - pages.append(LoginProloguePromoViewController(as: .notifications)) - pages.append(LoginProloguePromoViewController(as: .jetpack)) - } - setViewControllers([pages[0]], direction: .forward, animated: false) view.backgroundColor = WordPressAuthenticator.shared.style.prologueBackgroundColor diff --git a/WordPressAuthenticator/Signin/LoginProloguePromoViewController.swift b/WordPressAuthenticator/Signin/LoginProloguePromoViewController.swift deleted file mode 100644 index c9fc81cac..000000000 --- a/WordPressAuthenticator/Signin/LoginProloguePromoViewController.swift +++ /dev/null @@ -1,190 +0,0 @@ -import UIKit -import Lottie -import WordPressShared - -class LoginProloguePromoViewController: UIViewController { - fileprivate let type: PromoType - fileprivate let stackView: UIStackView - fileprivate let headingLabel: UILabel - fileprivate let animationHolder: UIView - fileprivate var animationView: AnimationView - - fileprivate struct Constants { - static let stackSpacing: CGFloat = 36.0 - static let stackHeightMultiplier: CGFloat = 0.87 - static let stackWidthMultiplier: CGFloat = 0.8 - static let labelMinHeight: CGFloat = 21.0 - static let labelMaxWidth: CGFloat = 600.0 - static let animationWidthHeightRatio: CGFloat = 0.6667 - } - - enum PromoType: String { - case post - case stats - case reader - case notifications - case jetpack - // new prologue carousel - case intro - case editor - case comments - case analytics - case discover - - var animationKey: String { - return rawValue - } - - var headlineText: String { - switch self { - case .post: - return NSLocalizedString("Publish from the park. Blog from the bus. Comment from the café. WordPress goes where you do.", comment: "shown in promotional screens during first launch") - case .stats: - return NSLocalizedString("Watch readers from around the world read and interact with your site — in real time.", comment: "shown in promotional screens during first launch") - case .reader: - return NSLocalizedString("Catch up with your favorite sites and join the conversation anywhere, any time.", comment: "shown in promotional screens during first launch") - case .notifications: - return NSLocalizedString("Your notifications travel with you — see comments and likes as they happen.", comment: "shown in promotional screens during first launch") - case .jetpack: - return NSLocalizedString("Manage your Jetpack-powered site on the go — you've got WordPress in your pocket.", comment: "shown in promotional screens during first launch") - // new prologue carousel - case .intro: - return NSLocalizedString("Welcome to the world’s most popular website builder.", comment: "Shown in the prologue carousel (promotional screens) during first launch.") - case .editor: - return NSLocalizedString("With this powerful editor you can post on the go.", comment: "Shown in the prologue carousel (promotional screens) during first launch.") - case .comments: - return NSLocalizedString("See comments and notifications in real time.", comment: "Shown in the prologue carousel (promotional screens) during first launch.") - case .analytics: - return NSLocalizedString("Watch your audience grow with in-depth analytics.", comment: "Shown in the prologue carousel (promotional screens) during first launch.") - case .discover: - return NSLocalizedString("Follow your favorite sites and discover new blogs.", comment: "Shown in the prologue carousel (promotional screens) during first launch.") - } - } - - var headlineColor: UIColor { - if WordPressAuthenticator.shared.configuration.enableUnifiedCarousel { - return WordPressAuthenticator.shared.unifiedStyle?.textColor ?? WordPressAuthenticator.shared.style.secondaryTitleColor - } - - return WordPressAuthenticator.shared.style.prologueTitleColor - } - } - - init(as promoType: PromoType) { - type = promoType - stackView = UIStackView() - headingLabel = UILabel() - animationHolder = UIView() - - let bundle = WordPressAuthenticator.bundle - animationView = AnimationView(name: type.animationKey, bundle: bundle) - - super.init(nibName: nil, bundle: nil) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - setupBackground() - styleHeadingLabel() - setupLayout() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - animationView.currentProgress = 0.0 - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - animationView.play() - } - - private func setupBackground() { - view.backgroundColor = UIColor.clear - } - - private func didChangePreferredContentSize() { - styleHeadingLabel() - } - - private func styleHeadingLabel() { - if WordPressAuthenticator.shared.configuration.enableUnifiedCarousel { - headingLabel.font = WPStyleGuide.serifFontForTextStyle(.title1) - headingLabel.textColor = type.headlineColor - headingLabel.text = type.headlineText - headingLabel.textAlignment = .center - headingLabel.numberOfLines = 0 - headingLabel.adjustsFontSizeToFitWidth = true - headingLabel.sizeToFit() - } else { - headingLabel.font = WPStyleGuide.mediumWeightFont(forStyle: .title3) - headingLabel.textColor = type.headlineColor - headingLabel.text = type.headlineText - headingLabel.textAlignment = .center - headingLabel.numberOfLines = 0 - headingLabel.adjustsFontSizeToFitWidth = true - headingLabel.sizeToFit() - } - } - - // MARK: layout - - private func setupLayout() { - view.addSubview(stackView) - stackView.addArrangedSubview(headingLabel) - stackView.addArrangedSubview(animationHolder) - animationHolder.addSubview(animationView) - - stackView.axis = .vertical - stackView.spacing = Constants.stackSpacing - stackView.alignment = .center - stackView.distribution = .fill - stackView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), - stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - stackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: Constants.stackWidthMultiplier), - stackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: Constants.stackHeightMultiplier) - ]) - - headingLabel.setContentHuggingPriority(.defaultLow, for: .vertical) - headingLabel.setContentCompressionResistancePriority(.required, for: .vertical) - headingLabel.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - headingLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: Constants.labelMinHeight), - headingLabel.widthAnchor.constraint(lessThanOrEqualToConstant: Constants.labelMaxWidth) - ]) - - animationHolder.setContentHuggingPriority(.defaultLow, for: .vertical) - animationHolder.setContentCompressionResistancePriority(.defaultHigh, for: .vertical) - animationHolder.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - animationHolder.widthAnchor.constraint(greaterThanOrEqualTo: animationHolder.heightAnchor, multiplier: Constants.animationWidthHeightRatio) - ]) - - animationView.contentMode = .scaleAspectFit - animationView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - animationView.leadingAnchor.constraint(equalTo: animationHolder.leadingAnchor), - animationView.trailingAnchor.constraint(equalTo: animationHolder.trailingAnchor), - animationView.topAnchor.constraint(equalTo: animationHolder.topAnchor), - animationView.bottomAnchor.constraint(equalTo: animationHolder.bottomAnchor) - ]) - } -} - -extension LoginProloguePromoViewController { - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { - didChangePreferredContentSize() - } - } -} diff --git a/WordPressAuthenticator/Signin/LoginPrologueViewController.swift b/WordPressAuthenticator/Signin/LoginPrologueViewController.swift deleted file mode 100644 index 5c99be2b0..000000000 --- a/WordPressAuthenticator/Signin/LoginPrologueViewController.swift +++ /dev/null @@ -1,626 +0,0 @@ -import UIKit -import Lottie -import WordPressShared -import WordPressUI -import WordPressKit - -class LoginPrologueViewController: LoginViewController { - - @IBOutlet private weak var topContainerView: UIView! - @IBOutlet private weak var buttonBlurEffectView: UIVisualEffectView! - private var buttonViewController: NUXButtonViewController? - var showCancel = false - - /// Blur effect on button container view - /// - private var blurEffect: UIBlurEffect.Style { - if #available(iOS 13.0, *) { - return .systemChromeMaterial - } - - return .regular - } - - /// Constraints on the button view container. - /// Used to adjust the button width in unified views. - @IBOutlet private weak var buttonViewLeadingConstraint: NSLayoutConstraint? - @IBOutlet private weak var buttonViewTrailingConstraint: NSLayoutConstraint? - private var defaultButtonViewMargin: CGFloat = 0 - - // Called when login button is tapped - var onLoginButtonTapped: (() -> Void)? - - private let configuration = WordPressAuthenticator.shared.configuration - private let style = WordPressAuthenticator.shared.style - - @available(iOS 13, *) - private lazy var storedCredentialsAuthenticator = StoredCredentialsAuthenticator(onCancel: { - // Since the authenticator has its own flow - self.tracker.resetState() - }) - - /// We can't rely on `isMovingToParent` to know if we need to track the `.prologue` step - /// because for the root view in an App, it's always `false`. We're relying this variiable - /// instead, since the `.prologue` step only needs to be tracked once. - /// - private var prologueFlowTracked = false - - // MARK: - Lifecycle Methods - - override func viewDidLoad() { - super.viewDidLoad() - - if let topContainerChildViewController = style.prologueTopContainerChildViewController() { - topContainerView.subviews.forEach { $0.removeFromSuperview() } - addChild(topContainerChildViewController) - topContainerView.addSubview(topContainerChildViewController.view) - topContainerChildViewController.didMove(toParent: self) - - topContainerChildViewController.view.translatesAutoresizingMaskIntoConstraints = false - topContainerView.pinSubviewToAllEdges(topContainerChildViewController.view) - } - - defaultButtonViewMargin = buttonViewLeadingConstraint?.constant ?? 0 - } - - override func styleBackground() { - guard let unifiedBackgroundColor = WordPressAuthenticator.shared.unifiedStyle?.viewControllerBackgroundColor else { - super.styleBackground() - return - } - - view.backgroundColor = unifiedBackgroundColor - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - configureButtonVC() - navigationController?.setNavigationBarHidden(true, animated: false) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - // We've found some instances where the iCloud Keychain login flow was being started - // when the device was idle and the app was logged out and in the background. I couldn't - // find precise reproduction steps for this issue but my guess is that some background - // operation is triggering a call to this method while the app is in the background. - // The proposed solution is based off this StackOverflow reply: - // - // https://stackoverflow.com/questions/30584356/viewdidappear-is-called-when-app-is-started-due-to-significant-location-change - // - guard UIApplication.shared.applicationState != .background else { - return - } - - WordPressAuthenticator.track(.loginPrologueViewed) - - tracker.set(flow: .prologue) - - if !prologueFlowTracked { - tracker.track(step: .prologue) - prologueFlowTracked = true - } else { - tracker.set(step: .prologue) - } - - showiCloudKeychainLoginFlow() - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - self.navigationController?.setNavigationBarHidden(false, animated: animated) - } - - override var supportedInterfaceOrientations: UIInterfaceOrientationMask { - return UIDevice.isPad() ? .all : .portrait - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - setButtonViewMargins(forWidth: view.frame.width) - } - - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - setButtonViewMargins(forWidth: size.width) - } - - // MARK: - iCloud Keychain Login - - /// Starts the iCloud Keychain login flow if the conditions are given. - /// - private func showiCloudKeychainLoginFlow() { - guard #available(iOS 13, *), - WordPressAuthenticator.shared.configuration.enableUnifiedAuth, - let navigationController = navigationController else { - return - } - - storedCredentialsAuthenticator.showPicker(from: navigationController) - } - - // MARK: - Segue - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - super.prepare(for: segue, sender: sender) - - if let vc = segue.destination as? NUXButtonViewController { - buttonViewController = vc - } - } - - private func configureButtonVC() { - guard let buttonViewController = buttonViewController else { - return - } - - guard configuration.enableUnifiedAuth else { - buildPrologueButtons(buttonViewController) - return - } - - buildUnifiedPrologueButtons(buttonViewController) - - buttonViewController.shadowLayoutGuide = view.safeAreaLayoutGuide - buttonViewController.topButtonStyle = WordPressAuthenticator.shared.style.prologuePrimaryButtonStyle - buttonViewController.bottomButtonStyle = WordPressAuthenticator.shared.style.prologueSecondaryButtonStyle - } - - /// Displays the old UI prologue buttons. - /// - private func buildPrologueButtons(_ buttonViewController: NUXButtonViewController) { - let loginTitle = NSLocalizedString("Log In", comment: "Button title. Tapping takes the user to the login form.") - let createTitle = NSLocalizedString("Sign up for WordPress.com", comment: "Button title. Tapping begins the process of creating a WordPress.com account.") - - buttonViewController.setupTopButton(title: loginTitle, isPrimary: false, accessibilityIdentifier: "Prologue Log In Button") { [weak self] in - self?.onLoginButtonTapped?() - self?.loginTapped() - } - - if configuration.enableSignUp { - buttonViewController.setupBottomButton(title: createTitle, isPrimary: true, accessibilityIdentifier: "Prologue Signup Button") { [weak self] in - self?.signupTapped() - } - } - - if showCancel { - let cancelTitle = NSLocalizedString("Cancel", comment: "Button title. Tapping it cancels the login flow.") - buttonViewController.setupTertiaryButton(title: cancelTitle, isPrimary: false) { [weak self] in - self?.dismiss(animated: true, completion: nil) - } - } - - buttonViewController.backgroundColor = style.buttonViewBackgroundColor - buttonBlurEffectView.isHidden = true - } - - /// Displays the Unified prologue buttons. - /// - private func buildUnifiedPrologueButtons(_ buttonViewController: NUXButtonViewController) { - let displayStrings = WordPressAuthenticator.shared.displayStrings - let loginTitle = displayStrings.continueWithWPButtonTitle - let siteAddressTitle = displayStrings.enterYourSiteAddressButtonTitle - - if configuration.continueWithSiteAddressFirst { - buildUnifiedPrologueButtonsWithSiteAddressFirst(buttonViewController, loginTitle: loginTitle, siteAddressTitle: siteAddressTitle) - return - } - - buildDefaultUnifiedPrologueButtons(buttonViewController, loginTitle: loginTitle, siteAddressTitle: siteAddressTitle) - } - - private func buildDefaultUnifiedPrologueButtons(_ buttonViewController: NUXButtonViewController, loginTitle: String, siteAddressTitle: String) { - - setButtonViewMargins(forWidth: view.frame.width) - - buttonViewController.setupTopButton(title: loginTitle, isPrimary: true, configureBodyFontForTitle: true, accessibilityIdentifier: "Prologue Continue Button", onTap: loginTapCallback()) - - if configuration.enableUnifiedAuth { - buttonViewController.setupBottomButton(title: siteAddressTitle, isPrimary: false, configureBodyFontForTitle: true, accessibilityIdentifier: "Prologue Self Hosted Button", onTap: siteAddressTapCallback()) - } - - showCancelIfNeccessary(buttonViewController) - - setButtonViewControllerBackground(buttonViewController) - } - - private func buildUnifiedPrologueButtonsWithSiteAddressFirst(_ buttonViewController: NUXButtonViewController, loginTitle: String, siteAddressTitle: String) { - guard configuration.enableUnifiedAuth == true else { - return - } - - setButtonViewMargins(forWidth: view.frame.width) - - buttonViewController.setupTopButton(title: siteAddressTitle, isPrimary: true, accessibilityIdentifier: "Prologue Self Hosted Button", onTap: siteAddressTapCallback()) - - buttonViewController.setupBottomButton(title: loginTitle, isPrimary: false, accessibilityIdentifier: "Prologue Continue Button", onTap: loginTapCallback()) - - showCancelIfNeccessary(buttonViewController) - - setButtonViewControllerBackground(buttonViewController) - } - - private func siteAddressTapCallback() -> NUXButtonViewController.CallBackType { - return { [weak self] in - self?.siteAddressTapped() - } - } - - private func loginTapCallback() -> NUXButtonViewController.CallBackType { - return { [weak self] in - guard let self = self else { - return - } - - self.tracker.track(click: .continueWithWordPressCom) - self.continueWithDotCom() - } - } - - private func showCancelIfNeccessary(_ buttonViewController: NUXButtonViewController) { - if showCancel { - let cancelTitle = NSLocalizedString("Cancel", comment: "Button title. Tapping it cancels the login flow.") - buttonViewController.setupTertiaryButton(title: cancelTitle, isPrimary: false) { [weak self] in - self?.dismiss(animated: true, completion: nil) - } - } - } - - private func setButtonViewControllerBackground(_ buttonViewController: NUXButtonViewController) { - // Fallback to setting the button background color to clear so the blur effect blurs the Prologue background color. - let buttonsBackgroundColor = WordPressAuthenticator.shared.unifiedStyle?.prologueButtonsBackgroundColor ?? .clear - buttonViewController.backgroundColor = buttonsBackgroundColor - - /// If host apps provide a background color for the prologue buttons: - /// 1. Hide the blur effect - /// 2. Set the background color of the view controller to prologueViewBackgroundColor - let prologueViewBackgroundColor = WordPressAuthenticator.shared.unifiedStyle?.prologueViewBackgroundColor ?? .clear - - guard prologueViewBackgroundColor.cgColor == buttonsBackgroundColor.cgColor else { - buttonBlurEffectView.effect = UIBlurEffect(style: blurEffect) - return - } - - buttonBlurEffectView.isHidden = true - view.backgroundColor = prologueViewBackgroundColor - } - - // MARK: - Actions - - /// Old UI. "Log In" button action. - /// - private func loginTapped() { - tracker.set(source: .default) - - guard let vc = LoginPrologueLoginMethodViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate to LoginPrologueLoginMethodViewController from LoginPrologueViewController") - return - } - - vc.transitioningDelegate = self - - // Continue with WordPress.com button action - vc.emailTapped = { [weak self] in - guard let self = self else { - return - } - - self.presentLoginEmailView() - } - - // Continue with Google button action - vc.googleTapped = { [weak self] in - self?.googleTapped() - } - - // Site address text link button action - vc.selfHostedTapped = { [weak self] in - self?.loginToSelfHostedSite() - } - - // Sign In With Apple (SIWA) button action - vc.appleTapped = { [weak self] in - self?.appleTapped() - } - - vc.modalPresentationStyle = .custom - navigationController?.present(vc, animated: true, completion: nil) - } - - /// Old UI. "Sign up with WordPress.com" button action. - /// - private func signupTapped() { - tracker.set(source: .default) - - // This stat is part of a funnel that provides critical information. - // Before making ANY modification to this stat please refer to: p4qSXL-35X-p2 - WordPressAuthenticator.track(.signupButtonTapped) - - guard let vc = LoginPrologueSignupMethodViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate to LoginPrologueSignupMethodViewController") - return - } - - vc.loginFields = self.loginFields - vc.dismissBlock = dismissBlock - vc.transitioningDelegate = self - vc.modalPresentationStyle = .custom - - vc.emailTapped = { [weak self] in - guard let self = self else { - return - } - - guard self.configuration.enableUnifiedAuth else { - self.presentSignUpEmailView() - return - } - - self.presentUnifiedSignupView() - } - - vc.googleTapped = { [weak self] in - guard let self = self else { - return - } - - guard self.configuration.enableUnifiedAuth else { - self.presentGoogleSignupView() - return - } - - self.presentUnifiedGoogleView() - } - - vc.appleTapped = { [weak self] in - self?.appleTapped() - } - - navigationController?.present(vc, animated: true, completion: nil) - } - - private func appleTapped() { - AppleAuthenticator.sharedInstance.delegate = self - AppleAuthenticator.sharedInstance.showFrom(viewController: self) - } - - private func googleTapped() { - guard configuration.enableUnifiedAuth else { - GoogleAuthenticator.sharedInstance.loginDelegate = self - GoogleAuthenticator.sharedInstance.showFrom(viewController: self, loginFields: loginFields, for: .login) - return - } - - presentUnifiedGoogleView() - } - - /// Unified "Continue with WordPress.com" prologue button action. - /// - private func continueWithDotCom() { - guard let vc = GetStartedViewController.instantiate(from: .getStarted) else { - DDLogError("Failed to navigate from LoginPrologueViewController to GetStartedViewController") - return - } - - navigationController?.pushViewController(vc, animated: true) - } - - /// Unified "Enter your existing site address" prologue button action. - /// - private func siteAddressTapped() { - tracker.track(click: .loginWithSiteAddress) - - loginToSelfHostedSite() - } - - private func presentSignUpEmailView() { - guard let toVC = SignupEmailViewController.instantiate(from: .signup) else { - DDLogError("Failed to navigate to SignupEmailViewController") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - private func presentUnifiedSignupView() { - guard let toVC = UnifiedSignupViewController.instantiate(from: .unifiedSignup) else { - DDLogError("Failed to navigate to UnifiedSignupViewController") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - private func presentLoginEmailView() { - guard let toVC = LoginEmailViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate to LoginEmailVC from LoginPrologueVC") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - private func presentGetStartedView() { - guard let toVC = GetStartedViewController.instantiate(from: .getStarted) else { - DDLogError("Failed to navigate to GetStartedViewController") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - // Shows the VC that handles both Google login & signup. - private func presentUnifiedGoogleView() { - guard let toVC = GoogleAuthViewController.instantiate(from: .googleAuth) else { - DDLogError("Failed to navigate to GoogleAuthViewController from LoginPrologueVC") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - // Shows the VC that handles only Google signup. - private func presentGoogleSignupView() { - guard let toVC = SignupGoogleViewController.instantiate(from: .signup) else { - DDLogError("Failed to navigate to SignupGoogleViewController from LoginPrologueVC") - return - } - - navigationController?.pushViewController(toVC, animated: true) - } - - private func presentWPLogin() { - guard let vc = LoginWPComViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate from LoginPrologueViewController to LoginWPComViewController") - return - } - - vc.loginFields = self.loginFields - vc.dismissBlock = dismissBlock - vc.errorToPresent = errorToPresent - - navigationController?.pushViewController(vc, animated: true) - } - - private func presentUnifiedPassword() { - guard let vc = PasswordViewController.instantiate(from: .password) else { - DDLogError("Failed to navigate from LoginPrologueViewController to PasswordViewController") - return - } - - vc.loginFields = loginFields - navigationController?.pushViewController(vc, animated: true) - } - -} - -// MARK: - LoginFacadeDelegate - -extension LoginPrologueViewController { - - // Used by SIWA when logging with with a passwordless, 2FA account. - // - func needsMultifactorCode(forUserID userID: Int, andNonceInfo nonceInfo: SocialLogin2FANonceInfo) { - configureViewLoading(false) - socialNeedsMultifactorCode(forUserID: userID, andNonceInfo: nonceInfo) - } - -} - -// MARK: - AppleAuthenticatorDelegate - -extension LoginPrologueViewController: AppleAuthenticatorDelegate { - - func showWPComLogin(loginFields: LoginFields) { - self.loginFields = loginFields - - guard WordPressAuthenticator.shared.configuration.enableUnifiedAuth else { - presentWPLogin() - return - } - - presentUnifiedPassword() - } - - func showApple2FA(loginFields: LoginFields) { - self.loginFields = loginFields - signInAppleAccount() - } - - func authFailedWithError(message: String) { - displayErrorAlert(message, sourceTag: .loginApple) - } - -} - -// MARK: - GoogleAuthenticatorLoginDelegate - -extension LoginPrologueViewController: GoogleAuthenticatorLoginDelegate { - - func googleFinishedLogin(credentials: AuthenticatorCredentials, loginFields: LoginFields) { - self.loginFields = loginFields - syncWPComAndPresentEpilogue(credentials: credentials) - } - - func googleNeedsMultifactorCode(loginFields: LoginFields) { - self.loginFields = loginFields - - guard let vc = Login2FAViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate from LoginViewController to Login2FAViewController") - return - } - - vc.loginFields = loginFields - vc.dismissBlock = dismissBlock - vc.errorToPresent = errorToPresent - - navigationController?.pushViewController(vc, animated: true) - } - - func googleExistingUserNeedsConnection(loginFields: LoginFields) { - self.loginFields = loginFields - - guard let vc = LoginWPComViewController.instantiate(from: .login) else { - DDLogError("Failed to navigate from Google Login to LoginWPComViewController (password VC)") - return - } - - vc.loginFields = loginFields - vc.dismissBlock = dismissBlock - vc.errorToPresent = errorToPresent - - navigationController?.pushViewController(vc, animated: true) - } - - func googleLoginFailed(errorTitle: String, errorDescription: String, loginFields: LoginFields) { - self.loginFields = loginFields - - let socialErrorVC = LoginSocialErrorViewController(title: errorTitle, description: errorDescription) - let socialErrorNav = LoginNavigationController(rootViewController: socialErrorVC) - socialErrorVC.delegate = self - socialErrorVC.loginFields = loginFields - socialErrorVC.modalPresentationStyle = .fullScreen - present(socialErrorNav, animated: true) - } - -} - -// MARK: - Button View Sizing - -private extension LoginPrologueViewController { - - /// Resize the button view based on trait collection. - /// Used only in unified views. - /// - func setButtonViewMargins(forWidth viewWidth: CGFloat) { - - guard configuration.enableUnifiedAuth else { - return - } - - guard traitCollection.horizontalSizeClass == .regular && - traitCollection.verticalSizeClass == .regular else { - buttonViewLeadingConstraint?.constant = defaultButtonViewMargin - buttonViewTrailingConstraint?.constant = defaultButtonViewMargin - return - } - - let marginMultiplier = UIDevice.current.orientation.isLandscape ? - ButtonViewMarginMultipliers.ipadLandscape : - ButtonViewMarginMultipliers.ipadPortrait - - let margin = viewWidth * marginMultiplier - - buttonViewLeadingConstraint?.constant = margin - buttonViewTrailingConstraint?.constant = margin - } - - private enum ButtonViewMarginMultipliers { - static let ipadPortrait: CGFloat = 0.1667 - static let ipadLandscape: CGFloat = 0.25 - } - -}