diff --git a/WordPressAuthenticator.podspec b/WordPressAuthenticator.podspec index 7afc98ffd..66400426a 100644 --- a/WordPressAuthenticator.podspec +++ b/WordPressAuthenticator.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "WordPressAuthenticator" - s.version = "1.10.5" + s.version = "1.10.6-beta.1" s.summary = "WordPressAuthenticator implements an easy and elegant way to authenticate your WordPress Apps." s.description = <<-DESC diff --git a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift index 2224db768..0fa5e7b4e 100644 --- a/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift +++ b/WordPressAuthenticator/Authenticator/WordPressAuthenticatorDisplayStrings.swift @@ -25,6 +25,6 @@ public extension WordPressAuthenticatorDisplayStrings { static var defaultStrings: WordPressAuthenticatorDisplayStrings { return WordPressAuthenticatorDisplayStrings(emailLoginInstructions: NSLocalizedString("Log in to your WordPress.com account with your email address.", comment: "Instruction text on the login's email address screen."), jetpackLoginInstructions: NSLocalizedString("Log in to the WordPress.com account you used to connect Jetpack.", comment: "Instruction text on the login's email address screen."), - siteLoginInstructions: NSLocalizedString("Enter the address of your WordPress site you'd like to connect.", comment: "Instruction text on the login's site addresss screen.")) + siteLoginInstructions: NSLocalizedString("Enter the address of the WordPress site you'd like to connect.", comment: "Instruction text on the login's site addresss screen.")) } } diff --git a/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift b/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift index 29c086e88..7f4e3c031 100644 --- a/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift +++ b/WordPressAuthenticator/Extensions/WPStyleGuide+Login.swift @@ -47,6 +47,9 @@ extension WPStyleGuide { onePasswordButton.setImage(.onePasswordImage, for: .normal) onePasswordButton.sizeToFit() + onePasswordButton.accessibilityLabel = + NSLocalizedString("Fill with password manager", comment: "The password manager button in login pages. The button opens a dialog showing which password manager to use (e.g. 1Password, LastPass). ") + textField.rightView = onePasswordButton textField.rightViewMode = .always diff --git a/WordPressAuthenticator/NUX/WPWalkthroughTextField.m b/WordPressAuthenticator/NUX/WPWalkthroughTextField.m index 81c0c788c..e8896561c 100644 --- a/WordPressAuthenticator/NUX/WPWalkthroughTextField.m +++ b/WordPressAuthenticator/NUX/WPWalkthroughTextField.m @@ -120,6 +120,8 @@ - (void)configureSecureTextEntryToggle { [self.secureTextEntryToggle addTarget:self action:@selector(secureTextEntryToggleAction:) forControlEvents:UIControlEventTouchUpInside]; [self updateSecureTextEntryToggleImage]; + [self updateSecureTextEntryForAccessibility]; + self.rightView = self.secureTextEntryToggle; self.rightViewMode = UITextFieldViewModeAlways; } @@ -253,6 +255,7 @@ - (void)setSecureTextEntry:(BOOL)secureTextEntry [super setSecureTextEntry:secureTextEntry]; [self updateSecureTextEntryToggleImage]; + [self updateSecureTextEntryForAccessibility]; } - (void)secureTextEntryToggleAction:(id)sender @@ -272,4 +275,17 @@ - (void)updateSecureTextEntryToggleImage [self.secureTextEntryToggle sizeToFit]; } +- (void)updateSecureTextEntryForAccessibility +{ + self.secureTextEntryToggle.accessibilityLabel = NSLocalizedString(@"Show password", @"Accessibility label for the “Show password“ button in the login page's password field."); + + NSString *accessibilityValue; + if (self.isSecureTextEntry) { + accessibilityValue = NSLocalizedString(@"Hidden", "Accessibility value if login page's password field is hiding the password (i.e. with asterisks)."); + } else { + accessibilityValue = NSLocalizedString(@"Shown", "Accessibility value if login page's password field is displaying the password."); + } + self.secureTextEntryToggle.accessibilityValue = accessibilityValue; +} + @end diff --git a/WordPressAuthenticator/Signin/LoginSelfHostedViewController.swift b/WordPressAuthenticator/Signin/LoginSelfHostedViewController.swift index 8db550889..a009818ec 100644 --- a/WordPressAuthenticator/Signin/LoginSelfHostedViewController.swift +++ b/WordPressAuthenticator/Signin/LoginSelfHostedViewController.swift @@ -36,6 +36,7 @@ class LoginSelfHostedViewController: LoginViewController, NUXKeyboardResponder { localizeControls() setupOnePasswordButtonIfNeeded() displayLoginMessage("") + configureForAcessibility() } @@ -90,6 +91,26 @@ class LoginSelfHostedViewController: LoginViewController, NUXKeyboardResponder { } + /// Sets up necessary accessibility labels and attributes for the all the UI elements in self. + /// + private func configureForAcessibility() { + usernameField.accessibilityLabel = + NSLocalizedString("Username", comment: "Accessibility label for the username text field in the self-hosted login page.") + passwordField.accessibilityLabel = + NSLocalizedString("Password", comment: "Accessibility label for the password text field in the self-hosted login page.") + + if UIAccessibility.isVoiceOverRunning { + // Remove the placeholder if VoiceOver is running. VoiceOver speaks the label and the + // placeholder together. In this case, both labels and placeholders are the same so it's + // like VoiceOver is reading the same thing twice. + usernameField.placeholder = nil + passwordField.placeholder = nil + } + + forgotPasswordButton.accessibilityTraits = .link + } + + /// Sets up a 1Password button if 1Password is available. /// @objc func setupOnePasswordButtonIfNeeded() { @@ -294,7 +315,9 @@ extension LoginSelfHostedViewController { configureViewLoading(false) let err = error as NSError if err.code == 403 { - displayError(message: NSLocalizedString("It looks like this username/password isn't associated with this site.", comment: "An error message shown during log in when the username or password is incorrect.")) + let message = NSLocalizedString("It looks like this username/password isn't associated with this site.", + comment: "An error message shown during log in when the username or password is incorrect.") + displayError(message: message, moveVoiceOverFocus: true) } else { displayError(error as NSError, sourceTag: sourceTag) } diff --git a/WordPressAuthenticator/Signin/LoginSiteAddressViewController.swift b/WordPressAuthenticator/Signin/LoginSiteAddressViewController.swift index e51faf76b..04b1d6238 100644 --- a/WordPressAuthenticator/Signin/LoginSiteAddressViewController.swift +++ b/WordPressAuthenticator/Signin/LoginSiteAddressViewController.swift @@ -37,6 +37,7 @@ class LoginSiteAddressViewController: LoginViewController, NUXKeyboardResponder override func viewDidLoad() { super.viewDidLoad() localizeControls() + configureForAccessibility() } @@ -90,6 +91,12 @@ class LoginSiteAddressViewController: LoginViewController, NUXKeyboardResponder siteAddressHelpButton.titleLabel?.numberOfLines = 0 } + /// Sets up necessary accessibility labels and attributes for the all the UI elements in self. + /// + private func configureForAccessibility() { + siteURLField.accessibilityLabel = + NSLocalizedString("Site address", comment: "Accessibility label of the site address field shown when adding a self-hosted site.") + } /// Configures the content of the text fields based on what is saved in `loginFields`. /// @@ -178,7 +185,7 @@ class LoginSiteAddressViewController: LoginViewController, NUXKeyboardResponder let err = self.originalErrorOrError(error: error as NSError) if let xmlrpcValidatorError = err as? WordPressOrgXMLRPCValidatorError { - self.displayError(message: xmlrpcValidatorError.localizedDescription) + self.displayError(message: xmlrpcValidatorError.localizedDescription, moveVoiceOverFocus: true) } else if (err.domain == NSURLErrorDomain && err.code == NSURLErrorCannotFindHost) || (err.domain == NSURLErrorDomain && err.code == NSURLErrorNetworkConnectionLost) { @@ -186,7 +193,7 @@ class LoginSiteAddressViewController: LoginViewController, NUXKeyboardResponder let msg = NSLocalizedString( "The site at this address is not a WordPress site. For us to connect to it, the site must use WordPress.", comment: "Error message shown a URL does not point to an existing site.") - self.displayError(message: msg) + self.displayError(message: msg, moveVoiceOverFocus: true) } else { self.displayError(error as NSError, sourceTag: self.sourceTag) diff --git a/WordPressAuthenticator/Signin/LoginViewController.swift b/WordPressAuthenticator/Signin/LoginViewController.swift index a41528fda..68cfadde3 100644 --- a/WordPressAuthenticator/Signin/LoginViewController.swift +++ b/WordPressAuthenticator/Signin/LoginViewController.swift @@ -82,7 +82,13 @@ open class LoginViewController: NUXViewController, LoginFacadeDelegate { } /// Sets the text of the error label. - func displayError(message: String) { + /// + /// - Parameter message: The message to display in the `errorLabel`. If empty, the `errorLabel` + /// will be hidden. + /// - Parameter moveVoiceOverFocus: If `true`, moves the VoiceOver focus to the `errorLabel`. + /// You will want to set this to `true` if the error was caused after pressing a button + /// (e.g. Next button). + func displayError(message: String, moveVoiceOverFocus: Bool = false) { guard message.count > 0 else { errorLabel?.isHidden = true return @@ -90,6 +96,10 @@ open class LoginViewController: NUXViewController, LoginFacadeDelegate { errorLabel?.isHidden = false errorLabel?.text = message errorToPresent = nil + + if moveVoiceOverFocus, let errorLabel = errorLabel { + UIAccessibility.post(notification: .layoutChanged, argument: errorLabel) + } } private func mustShowLoginEpilogue() -> Bool {