diff --git a/Simplenote/AuthViewController+Swift.swift b/Simplenote/AuthViewController+Swift.swift index 14410db4..01599689 100644 --- a/Simplenote/AuthViewController+Swift.swift +++ b/Simplenote/AuthViewController+Swift.swift @@ -150,6 +150,8 @@ extension AuthViewController { if let title = descriptor.text { actionView.title = title + } else if let attributedTitle = descriptor.attributedText { + actionView.attributedTitle = attributedTitle } actionView.action = descriptor.selector @@ -167,6 +169,8 @@ extension AuthViewController { codeTextField.isHidden = !inputElements.contains(.code) actionsSeparatorView.isHidden = !inputElements.contains(.actionSeparator) + usernameField.stringValue = state.username + usernameField.textField?.nextResponder = passwordField.textField } /// Drops any Errors onscreen @@ -226,6 +230,11 @@ extension AuthViewController { func pushCodeLoginView() { pushNewAuthViewController(with: .loginWithCode, state: state) } + + @objc + func pushUsernameAndPasswordView() { + pushNewAuthViewController(with: .loginWithUsernameAndPassword, state: state) + } } diff --git a/Simplenote/AuthViewController.xib b/Simplenote/AuthViewController.xib index 99cfdb12..0ca3b430 100644 --- a/Simplenote/AuthViewController.xib +++ b/Simplenote/AuthViewController.xib @@ -142,7 +142,7 @@ - + diff --git a/Simplenote/AuthenticationMode.swift b/Simplenote/AuthenticationMode.swift index 988cd9c0..b71f9aed 100644 --- a/Simplenote/AuthenticationMode.swift +++ b/Simplenote/AuthenticationMode.swift @@ -125,7 +125,11 @@ extension AuthenticationMode { static var loginWithPassword: AuthenticationMode { buildLoginWithPasswordMode(header: LoginStrings.loginWithEmailEmailHeader) } - + + static var loginWithUsernameAndPassword: AuthenticationMode { + buildLoginWithPasswordMode(header: nil, includeUsername: true) + } + /// Auth Mode: Login with Username + Password + Rate Limiting Header /// static var loginWithPasswordRateLimited: AuthenticationMode { @@ -134,10 +138,11 @@ extension AuthenticationMode { /// Builds the loginWithPassword Mode with the specified Header /// - private static func buildLoginWithPasswordMode(header: String) -> AuthenticationMode { - AuthenticationMode(title: NSLocalizedString("Log In with Password", comment: "LogIn Interface Title"), + private static func buildLoginWithPasswordMode(header: String?, includeUsername: Bool = false) -> AuthenticationMode { + let inputElements: AuthenticationInputElements = includeUsername ? [.username, .password] : [.password] + return AuthenticationMode(title: NSLocalizedString("Log In with Password", comment: "LogIn Interface Title"), header: header, - inputElements: [.password], + inputElements: inputElements, actions: [ AuthenticationActionDescriptor(name: .primary, selector: #selector(AuthViewController.pressedLogInWithPassword), @@ -160,6 +165,10 @@ extension AuthenticationMode { AuthenticationActionDescriptor(name: .primary, selector: #selector(AuthViewController.pressedLoginWithMagicLink), text: MagicLinkStrings.primaryAction), + AuthenticationActionDescriptor(name: .secondary, + selector: #selector(AuthViewController.pushUsernameAndPasswordView), + text: nil, + attributedText: LoginStrings.usernameAndPasswordOption), AuthenticationActionDescriptor(name: .tertiary, selector: #selector(AuthViewController.wordpressSSOAction), text: LoginStrings.wordpressAction) @@ -214,6 +223,23 @@ private enum LoginStrings { static let loginWithEmailEmailHeader = NSLocalizedString("Enter the password for the account {{EMAIL}}", comment: "Header for Login With Password. Please preserve the {{EMAIL}} substring") static let loginWithEmailLimitHeader = NSLocalizedString("Log in with email failed, please enter the password for {{EMAIL}}", comment: "Header for Enter Password UI, when the user performed too many requests") + /// Returns a formatted Secondary Action String for Optional Username and password login + /// + static var usernameAndPasswordOption: NSAttributedString { + let output = NSMutableAttributedString(string: String(), attributes: [ + .font: NSFont.preferredFont(forTextStyle: .subheadline) + ]) + + let prefix = NSLocalizedString("We'll email you a code to log in, \nor you can", comment: "Option to login with username and password *PREFIX*: printed in dark color") + let suffix = NSLocalizedString("log in manually.", comment: "Option to login with username and password *SUFFIX*: Concatenated with a space, after the PREFIX, and printed in blue") + + output.append(string: prefix, foregroundColor: NSColor(studioColor: ColorStudio.gray60)) + output.append(string: " ") + output.append(string: suffix, foregroundColor: NSColor(studioColor: ColorStudio.spBlue60)) + + return output + } + } private enum MagicLinkStrings { diff --git a/Simplenote/NSMutableAttributedString+Simplenote.swift b/Simplenote/NSMutableAttributedString+Simplenote.swift index 872e0ca9..f9a933f0 100644 --- a/Simplenote/NSMutableAttributedString+Simplenote.swift +++ b/Simplenote/NSMutableAttributedString+Simplenote.swift @@ -21,8 +21,13 @@ extension NSMutableAttributedString { /// Appends the specified String /// - func append(string: String) { - let string = NSAttributedString(string: string) + func append(string: String, foregroundColor: NSColor? = nil) { + var attributes = [NSAttributedString.Key: Any]() + if let foregroundColor = foregroundColor { + attributes[.foregroundColor] = foregroundColor + } + + let string = NSAttributedString(string: string, attributes: attributes) append(string) }