diff --git a/WordPressAuthenticator.podspec b/WordPressAuthenticator.podspec index 53b8bae34..759b09ca5 100644 --- a/WordPressAuthenticator.podspec +++ b/WordPressAuthenticator.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| s.name = 'WordPressAuthenticator' - s.version = '2.0.0' + s.version = '2.0.1-beta.1' s.summary = 'WordPressAuthenticator implements an easy and elegant way to authenticate your WordPress Apps.' s.description = <<-DESC diff --git a/WordPressAuthenticator.xcodeproj/project.pbxproj b/WordPressAuthenticator.xcodeproj/project.pbxproj index 16c24aba6..e22e09888 100644 --- a/WordPressAuthenticator.xcodeproj/project.pbxproj +++ b/WordPressAuthenticator.xcodeproj/project.pbxproj @@ -166,6 +166,7 @@ D881A311256B5B4700FE5605 /* NavigateToEnterSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = D881A310256B5B4700FE5605 /* NavigateToEnterSite.swift */; }; D881A315256B5B5800FE5605 /* NavigateToEnterAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = D881A314256B5B5800FE5605 /* NavigateToEnterAccount.swift */; }; E8AF6B9EF50902F2117DFAF9 /* Pods_WordPressAuthenticatorTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A441EC80D2B8D2209C2E228 /* Pods_WordPressAuthenticatorTests.framework */; }; + EE633D02287560E50002DE03 /* UITableView+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE633D01287560E50002DE03 /* UITableView+Helpers.swift */; }; F11448EC258B827B0048203D /* URL+JetpackConnect.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11448EB258B827B0048203D /* URL+JetpackConnect.swift */; }; F12F9FB424D8A68E00771BCE /* AuthenticatorAnalyticsTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12F9FB324D8A68E00771BCE /* AuthenticatorAnalyticsTracker.swift */; }; F12F9FB824D8A7FC00771BCE /* AnalyticsTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12F9FB724D8A7FC00771BCE /* AnalyticsTrackerTests.swift */; }; @@ -378,6 +379,7 @@ D881A310256B5B4700FE5605 /* NavigateToEnterSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigateToEnterSite.swift; sourceTree = ""; }; D881A314256B5B5800FE5605 /* NavigateToEnterAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigateToEnterAccount.swift; sourceTree = ""; }; E9414A95E29F3297555AC92B /* Pods-WordPressAuthenticator.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressAuthenticator.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressAuthenticator/Pods-WordPressAuthenticator.debug.xcconfig"; sourceTree = ""; }; + EE633D01287560E50002DE03 /* UITableView+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+Helpers.swift"; sourceTree = ""; }; F11448EB258B827B0048203D /* URL+JetpackConnect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+JetpackConnect.swift"; sourceTree = ""; }; F12F9FB324D8A68E00771BCE /* AuthenticatorAnalyticsTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticatorAnalyticsTracker.swift; sourceTree = ""; }; F12F9FB724D8A7FC00771BCE /* AnalyticsTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsTrackerTests.swift; sourceTree = ""; }; @@ -685,6 +687,7 @@ F1C96668250BF53400EB529D /* UIViewController+Dismissal.swift */, CE9091FD249A720E00AB50BD /* UIView+AuthHelpers.swift */, F11448EB258B827B0048203D /* URL+JetpackConnect.swift */, + EE633D01287560E50002DE03 /* UITableView+Helpers.swift */, ); path = Extensions; sourceTree = ""; @@ -1181,6 +1184,7 @@ buildActionMask = 2147483647; files = ( CE73475624B77A3800A22660 /* SiteCredentialsViewController.swift in Sources */, + EE633D02287560E50002DE03 /* UITableView+Helpers.swift in Sources */, 982C8E7923021C20003F1BA0 /* LoginPrologueLoginMethodViewController.swift in Sources */, B5609144208A563800399AE4 /* LoginPrologueSignupMethodViewController.swift in Sources */, B56090D1208A4F5400399AE4 /* NUXViewController.swift in Sources */, diff --git a/WordPressAuthenticator/Analytics/AuthenticatorAnalyticsTracker.swift b/WordPressAuthenticator/Analytics/AuthenticatorAnalyticsTracker.swift index 07aebbfdb..35acc271d 100644 --- a/WordPressAuthenticator/Analytics/AuthenticatorAnalyticsTracker.swift +++ b/WordPressAuthenticator/Analytics/AuthenticatorAnalyticsTracker.swift @@ -142,6 +142,10 @@ public class AuthenticatorAnalyticsTracker { /// case continueWithWordPressCom = "continue_with_wordpress_com" + /// Tracked when the user clicks “What is WordPress.com?" button on the WordPress.com flow screen + /// + case whatIsWPCom = "what_is_wordpress_com" + /// Tracked when the user clicks “Login with site address” on the Prologue screen /// case loginWithSiteAddress = "login_with_site_address" diff --git a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorConfiguration.swift b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorConfiguration.swift index c57ad7c5b..48933f9d5 100644 --- a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorConfiguration.swift +++ b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorConfiguration.swift @@ -29,6 +29,12 @@ public struct WordPressAuthenticatorConfiguration { /// let wpcomAPIBaseURL: String + /// The URL of a webpage which has details about What is WordPress.com?. + /// + /// Displayed in the WordPress.com login page. The button/link will not be displayed if this value is nil. + /// + let whatIsWPComURL: String? + /// GoogleLogin Client ID /// let googleLoginClientId: String @@ -97,6 +103,7 @@ public struct WordPressAuthenticatorConfiguration { wpcomTermsOfServiceURL: String, wpcomBaseURL: String = WordPressComOAuthClient.WordPressComOAuthDefaultBaseUrl, wpcomAPIBaseURL: String = WordPressComOAuthClient.WordPressComOAuthDefaultApiBaseUrl, + whatIsWPComURL: String? = nil, googleLoginClientId: String, googleLoginServerClientId: String, googleLoginScheme: String, @@ -116,6 +123,7 @@ public struct WordPressAuthenticatorConfiguration { self.wpcomTermsOfServiceURL = wpcomTermsOfServiceURL self.wpcomBaseURL = wpcomBaseURL self.wpcomAPIBaseURL = wpcomAPIBaseURL + self.whatIsWPComURL = whatIsWPComURL self.googleLoginClientId = googleLoginClientId self.googleLoginServerClientId = googleLoginServerClientId self.googleLoginScheme = googleLoginScheme diff --git a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift index bce0c0504..1a4c38d95 100644 --- a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift +++ b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift @@ -45,6 +45,7 @@ public struct WordPressAuthenticatorDisplayStrings { public let textCodeButtonTitle: String public let loginTermsOfService: String public let signupTermsOfService: String + public let whatIsWPComLinkTitle: String /// Placeholder text for textfields. /// @@ -83,6 +84,7 @@ public struct WordPressAuthenticatorDisplayStrings { textCodeButtonTitle: String = defaultStrings.textCodeButtonTitle, loginTermsOfService: String = defaultStrings.loginTermsOfService, signupTermsOfService: String = defaultStrings.signupTermsOfService, + whatIsWPComLinkTitle: String = defaultStrings.whatIsWPComLinkTitle, getStartedTitle: String = defaultStrings.getStartedTitle, logInTitle: String = defaultStrings.logInTitle, signUpTitle: String = defaultStrings.signUpTitle, @@ -119,6 +121,7 @@ public struct WordPressAuthenticatorDisplayStrings { self.textCodeButtonTitle = textCodeButtonTitle self.loginTermsOfService = loginTermsOfService self.signupTermsOfService = signupTermsOfService + self.whatIsWPComLinkTitle = whatIsWPComLinkTitle self.getStartedTitle = getStartedTitle self.logInTitle = logInTitle self.signUpTitle = signUpTitle @@ -183,6 +186,8 @@ public extension WordPressAuthenticatorDisplayStrings { comment: "The button's title text to send a 2FA code via SMS text message."), loginTermsOfService: NSLocalizedString("By continuing, you agree to our _Terms of Service_.", comment: "Legal disclaimer for logging in. The underscores _..._ denote underline."), signupTermsOfService: NSLocalizedString("If you continue with Apple or Google and don't already have a WordPress.com account, you are creating an account and you agree to our _Terms of Service_.", comment: "Legal disclaimer for signing up. The underscores _..._ denote underline."), + whatIsWPComLinkTitle: NSLocalizedString("_What is WordPress.com?_", + comment: "Navigates to page with details about What is WordPress.com. The underscores _..._ denote underline."), getStartedTitle: NSLocalizedString("Get Started", comment: "View title for initial auth views."), logInTitle: NSLocalizedString("Log In", diff --git a/WordPressAuthenticator/Extensions/UITableView+Helpers.swift b/WordPressAuthenticator/Extensions/UITableView+Helpers.swift new file mode 100644 index 000000000..972468aa3 --- /dev/null +++ b/WordPressAuthenticator/Extensions/UITableView+Helpers.swift @@ -0,0 +1,20 @@ +import UIKit + +extension UITableView { + /// Called in view controller's `viewDidLayoutSubviews`. If table view has a footer view, calculates the new height. + /// If new height is different from current height, updates the footer view with the new height and reassigns the table footer view. + /// Note: make sure the top-level footer view (`tableView.tableFooterView`) is frame based as a container of the Auto Layout based subview. + func updateFooterHeight() { + if let footerView = tableFooterView { + let targetSize = CGSize(width: footerView.frame.width, height: 0) + let newSize = footerView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow) + let newHeight = newSize.height + var currentFrame = footerView.frame + if newHeight != currentFrame.size.height { + currentFrame.size.height = newHeight + footerView.frame = currentFrame + tableFooterView = footerView + } + } + } +} diff --git a/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift b/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift index 8fec50dd5..807e985ea 100644 --- a/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift +++ b/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift @@ -216,6 +216,26 @@ extension WPStyleGuide { return textButton(normal: attrStrNormal, highlighted: attrStrHighlight, font: font, alignment: .center) } + /// Creates a button to open a webpage with details about What is WordPress.com? + /// + /// - Returns: A properly styled UIButton + /// + class func whatIsWPComButton() -> UIButton { + let unifiedStyle = WordPressAuthenticator.shared.unifiedStyle + let originalStyle = WordPressAuthenticator.shared.style + let baseString = WordPressAuthenticator.shared.displayStrings.whatIsWPComLinkTitle + let textColor = unifiedStyle?.textSubtleColor ?? originalStyle.subheadlineColor + let linkColor = unifiedStyle?.textButtonColor ?? originalStyle.textButtonColor + + let attrStrNormal = baseString.underlined(color: textColor, underlineColor: linkColor) + let attrStrHighlight = baseString.underlined(color: textColor, underlineColor: linkColor) + let font = WPStyleGuide.mediumWeightFont(forStyle: .footnote) + + let button = textButton(normal: attrStrNormal, highlighted: attrStrHighlight, font: font, alignment: .center, forUnified: true) + button.titleLabel?.textAlignment = .center + return button + } + /// Creates a button to open our T&C. /// Specifically, the Sign Up verbiage on the Get Started view. /// - Returns: A properly styled UIButton diff --git a/WordPressAuthenticator/Unified Auth/View Related/Get Started/GetStartedViewController.swift b/WordPressAuthenticator/Unified Auth/View Related/Get Started/GetStartedViewController.swift index 85a417f23..5d252dcde 100644 --- a/WordPressAuthenticator/Unified Auth/View Related/Get Started/GetStartedViewController.swift +++ b/WordPressAuthenticator/Unified Auth/View Related/Get Started/GetStartedViewController.swift @@ -27,9 +27,13 @@ class GetStartedViewController: LoginViewController { private var shouldChangeVoiceOverFocus: Bool = false // Submit button displayed in the table footer. - private let continueButton: NUXButton = { + private lazy var continueButton: NUXButton = { let button = NUXButton() + button.translatesAutoresizingMaskIntoConstraints = false button.isPrimary = true + button.isEnabled = false + button.addTarget(self, action: #selector(handleSubmitButtonTapped(_:)), for: .touchUpInside) + button.accessibilityIdentifier = "Get Started Email Continue Button" let title = WordPressAuthenticator.shared.displayStrings.continueButtonTitle button.setTitle(title, for: .normal) @@ -53,7 +57,7 @@ class GetStartedViewController: LoginViewController { setupTable() registerTableViewCells() loadRows() - setupContinueButton() + setupTableFooterView() configureDivider() configureSocialButtons() } @@ -87,6 +91,11 @@ class GetStartedViewController: LoginViewController { hiddenPasswordField?.isAccessibilityElement = false } + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + tableView.updateFooterHeight() + } + // MARK: - Overrides override func styleBackground() { @@ -160,15 +169,30 @@ private extension GetStartedViewController { setTableViewMargins(forWidth: view.frame.width) } - func setupContinueButton() { - let tableFooter = UIView(frame: Constants.footerFrame) - tableFooter.addSubview(continueButton) - tableFooter.pinSubviewToSafeArea(continueButton, insets: Constants.footerButtonInsets) - continueButton.translatesAutoresizingMaskIntoConstraints = false - continueButton.isEnabled = false - continueButton.addTarget(self, action: #selector(handleSubmitButtonTapped(_:)), for: .touchUpInside) - continueButton.accessibilityIdentifier = "Get Started Email Continue Button" - tableView.tableFooterView = tableFooter + func setupTableFooterView() { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .fill + stackView.spacing = Constants.FooterStackView.spacing + stackView.layoutMargins = Constants.FooterStackView.layoutMargins + stackView.isLayoutMarginsRelativeArrangement = true + + stackView.addArrangedSubview(continueButton) + + if WordPressAuthenticator.shared.configuration.whatIsWPComURL != nil { + let stackViewWithCenterAlignment = UIStackView() + stackViewWithCenterAlignment.axis = .vertical + stackViewWithCenterAlignment.alignment = .center + + let button = WPStyleGuide.whatIsWPComButton() + button.addTarget(self, action: #selector(whatIsWPComButtonTapped(_:)), for: .touchUpInside) + stackViewWithCenterAlignment.addArrangedSubview(button) + + stackView.addArrangedSubview(stackViewWithCenterAlignment) + } + + tableView.tableFooterView = stackView + tableView.updateFooterHeight() } /// Style the "OR" divider. @@ -190,6 +214,17 @@ private extension GetStartedViewController { validateForm() } + // MARK: - What is WordPress.com Button Action + + @IBAction func whatIsWPComButtonTapped(_ sender: UIButton) { + tracker.track(click: .whatIsWPCom) + guard let whatIsWPCom = WordPressAuthenticator.shared.configuration.whatIsWPComURL, + let url = URL(string: whatIsWPCom) else { + return + } + UIApplication.shared.open(url) + } + // MARK: - Hidden Password Field Action @IBAction func handlePasswordFieldDidChange(_ sender: UITextField) { @@ -318,8 +353,10 @@ private extension GetStartedViewController { } enum Constants { - static let footerFrame = CGRect(x: 0, y: 0, width: 0, height: 44) - static let footerButtonInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + enum FooterStackView { + static let spacing = 16.0 + static let layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + } } }