mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-22 23:58:36 +01:00
Add login/logout support
This commit is contained in:
parent
8f5f856e49
commit
034aabbfff
@ -243,6 +243,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
self.delegate = FeedlyAccountDelegate(dataFolder: dataFolder, transport: transport, api: FeedlyAccountDelegate.environment)
|
||||
case .feedWrangler:
|
||||
self.delegate = FeedWranglerAccountDelegate(dataFolder: dataFolder, transport: transport)
|
||||
case .newsBlur:
|
||||
self.delegate = NewsBlurAccountDelegate(dataFolder: dataFolder, transport: transport)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@ -325,6 +327,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
ReaderAPIAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint, completion: completion)
|
||||
case .feedWrangler:
|
||||
FeedWranglerAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
|
||||
case .newsBlur:
|
||||
NewsBlurAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
179DB28CF49F73A945EBF5DB /* NewsBlurLoginResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB088236E3236010462E8 /* NewsBlurLoginResponse.swift */; };
|
||||
3B3A33E7238D3D6800314204 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A33E6238D3D6800314204 /* Secrets.swift */; };
|
||||
3B826DA72385C81C00FC1ADB /* FeedWranglerAuthorizationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826D9E2385C81C00FC1ADB /* FeedWranglerAuthorizationResult.swift */; };
|
||||
3B826DA82385C81C00FC1ADB /* FeedWranglerFeedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826D9F2385C81C00FC1ADB /* FeedWranglerFeedItem.swift */; };
|
||||
@ -63,6 +64,8 @@
|
||||
552032FD229D5D5A009559E0 /* ReaderAPITagging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032F2229D5D5A009559E0 /* ReaderAPITagging.swift */; };
|
||||
552032FE229D5D5A009559E0 /* ReaderAPIAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032F3229D5D5A009559E0 /* ReaderAPIAccountDelegate.swift */; };
|
||||
55203300229D5D5A009559E0 /* ReaderAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032F5229D5D5A009559E0 /* ReaderAPICaller.swift */; };
|
||||
769F295938E5A30D03DFF88F /* NewsBlurAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769F2A8DF190549E24B5D110 /* NewsBlurAccountDelegate.swift */; };
|
||||
769F2BA02EF5F329CDE45F5A /* NewsBlurAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769F275FD5D942502C5B4716 /* NewsBlurAPICaller.swift */; };
|
||||
841973FE1F6DD1BC006346C4 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973EF1F6DD19E006346C4 /* RSCore.framework */; };
|
||||
841973FF1F6DD1C5006346C4 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973FA1F6DD1AC006346C4 /* RSParser.framework */; };
|
||||
841974011F6DD1EC006346C4 /* Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974001F6DD1EC006346C4 /* Folder.swift */; };
|
||||
@ -220,6 +223,7 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
179DB088236E3236010462E8 /* NewsBlurLoginResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurLoginResponse.swift; sourceTree = "<group>"; };
|
||||
3B3A33E6238D3D6800314204 /* Secrets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Secrets.swift; path = ../../Shared/Secrets.swift; sourceTree = "<group>"; };
|
||||
3B826D9E2385C81C00FC1ADB /* FeedWranglerAuthorizationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAuthorizationResult.swift; sourceTree = "<group>"; };
|
||||
3B826D9F2385C81C00FC1ADB /* FeedWranglerFeedItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerFeedItem.swift; sourceTree = "<group>"; };
|
||||
@ -278,6 +282,8 @@
|
||||
552032F2229D5D5A009559E0 /* ReaderAPITagging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPITagging.swift; sourceTree = "<group>"; };
|
||||
552032F3229D5D5A009559E0 /* ReaderAPIAccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPIAccountDelegate.swift; sourceTree = "<group>"; };
|
||||
552032F5229D5D5A009559E0 /* ReaderAPICaller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPICaller.swift; sourceTree = "<group>"; };
|
||||
769F275FD5D942502C5B4716 /* NewsBlurAPICaller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurAPICaller.swift; sourceTree = "<group>"; };
|
||||
769F2A8DF190549E24B5D110 /* NewsBlurAccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurAccountDelegate.swift; sourceTree = "<group>"; };
|
||||
841973E81F6DD19E006346C4 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
||||
841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
|
||||
841974001F6DD1EC006346C4 /* Folder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folder.swift; sourceTree = "<group>"; };
|
||||
@ -435,6 +441,14 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
179DBD810D353D9CED7C3BED /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
179DB088236E3236010462E8 /* NewsBlurLoginResponse.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3B826D9D2385C81C00FC1ADB /* FeedWrangler */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -523,6 +537,16 @@
|
||||
path = ReaderAPI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
769F2630AF8DC873D4A73567 /* NewsBlur */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
769F2A8DF190549E24B5D110 /* NewsBlurAccountDelegate.swift */,
|
||||
769F275FD5D942502C5B4716 /* NewsBlurAPICaller.swift */,
|
||||
179DBD810D353D9CED7C3BED /* Models */,
|
||||
);
|
||||
path = NewsBlur;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
841973E91F6DD19E006346C4 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -622,6 +646,7 @@
|
||||
8469F80F1F6DC3C10084783E /* Frameworks */,
|
||||
D511EEB4202422BB00712EC3 /* xcconfig */,
|
||||
848934FA1F62484F00CEBD24 /* Info.plist */,
|
||||
769F2630AF8DC873D4A73567 /* NewsBlur */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
usesTabs = 1;
|
||||
@ -1107,6 +1132,9 @@
|
||||
9EF2602C23C91FFE006D160C /* FeedlyGetUpdatedArticleIdsOperation.swift in Sources */,
|
||||
3B826DAA2385C81C00FC1ADB /* FeedWranglerSubscription.swift in Sources */,
|
||||
3B826DAC2385C81C00FC1ADB /* FeedWranglerAccountDelegate.swift in Sources */,
|
||||
769F295938E5A30D03DFF88F /* NewsBlurAccountDelegate.swift in Sources */,
|
||||
769F2BA02EF5F329CDE45F5A /* NewsBlurAPICaller.swift in Sources */,
|
||||
179DB28CF49F73A945EBF5DB /* NewsBlurLoginResponse.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -17,6 +17,7 @@ public enum CredentialsType: String {
|
||||
case basic = "password"
|
||||
case feedWranglerBasic = "feedWranglerBasic"
|
||||
case feedWranglerToken = "feedWranglerToken"
|
||||
case newsBlur = "newsBlur"
|
||||
case readerBasic = "readerBasic"
|
||||
case readerAPIKey = "readerAPIKey"
|
||||
case oauthAccessToken = "oauthAccessToken"
|
||||
|
@ -33,7 +33,12 @@ public extension URLRequest {
|
||||
])
|
||||
case .feedWranglerToken:
|
||||
self.url = url.appendingQueryItem(URLQueryItem(name: "access_token", value: credentials.secret))
|
||||
case .readerBasic:
|
||||
case .newsBlur:
|
||||
setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||
httpMethod = "POST"
|
||||
let postData = "username=\(credentials.username)&password=\(credentials.secret)"
|
||||
httpBody = postData.data(using: String.Encoding.utf8)
|
||||
case .readerBasic:
|
||||
setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||
httpMethod = "POST"
|
||||
var postData = URLComponents()
|
||||
|
@ -0,0 +1,26 @@
|
||||
//
|
||||
// NewsBlurLoginResponse.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Anh Quang Do on 2020-03-09.
|
||||
// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NewsBlurLoginResponse: Decodable {
|
||||
var code: Int
|
||||
var errors: LoginError?
|
||||
|
||||
struct LoginError: Decodable {
|
||||
var username: [String]?
|
||||
var others: [String]?
|
||||
}
|
||||
}
|
||||
|
||||
extension NewsBlurLoginResponse.LoginError {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case username = "username"
|
||||
case others = "__all__"
|
||||
}
|
||||
}
|
72
Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift
Normal file
72
Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// NewsBlurAPICaller.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Anh-Quang Do on 3/9/20.
|
||||
// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSWeb
|
||||
|
||||
enum NewsBlurError: LocalizedError {
|
||||
case general(message: String)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .general(let message):
|
||||
return message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class NewsBlurAPICaller: NSObject {
|
||||
|
||||
private let baseURL = URL(string: "https://www.newsblur.com/")!
|
||||
private var transport: Transport!
|
||||
|
||||
var credentials: Credentials?
|
||||
weak var accountMetadata: AccountMetadata?
|
||||
|
||||
init(transport: Transport!) {
|
||||
super.init()
|
||||
self.transport = transport
|
||||
}
|
||||
|
||||
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
let url = baseURL.appendingPathComponent("api/login")
|
||||
let request = URLRequest(url: url, credentials: credentials)
|
||||
|
||||
transport.send(request: request, resultType: NewsBlurLoginResponse.self) { result in
|
||||
switch result {
|
||||
case .success(_, let payload):
|
||||
guard payload?.code != -1 else {
|
||||
let error = payload?.errors?.username ?? payload?.errors?.others
|
||||
if let message = error?.first {
|
||||
completion(.failure(NewsBlurError.general(message: message)))
|
||||
} else {
|
||||
completion(.failure(NewsBlurError.general(message: "Failed to log in")))
|
||||
}
|
||||
return
|
||||
}
|
||||
completion(.success(self.credentials))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func logout(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
let url = baseURL.appendingPathComponent("api/logout")
|
||||
let request = URLRequest(url: url, credentials: credentials)
|
||||
|
||||
transport.send(request: request) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
146
Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift
Normal file
146
Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift
Normal file
@ -0,0 +1,146 @@
|
||||
//
|
||||
// NewsBlurAccountDelegate.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Anh-Quang Do on 3/9/20.
|
||||
// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
final class NewsBlurAccountDelegate: AccountDelegate {
|
||||
|
||||
var behaviors: AccountBehaviors = []
|
||||
|
||||
var isOPMLImportInProgress: Bool = false
|
||||
var server: String? = "newsblur.com"
|
||||
var credentials: Credentials? {
|
||||
didSet {
|
||||
caller.credentials = credentials
|
||||
}
|
||||
}
|
||||
|
||||
var accountMetadata: AccountMetadata? = nil
|
||||
var refreshProgress = DownloadProgress(numberOfTasks: 0)
|
||||
|
||||
private let caller: NewsBlurAPICaller
|
||||
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "NewsBlur")
|
||||
private let database: SyncDatabase
|
||||
|
||||
init(dataFolder: String, transport: Transport?) {
|
||||
if let transport = transport {
|
||||
caller = NewsBlurAPICaller(transport: transport)
|
||||
} else {
|
||||
let sessionConfiguration = URLSessionConfiguration.default
|
||||
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
|
||||
sessionConfiguration.timeoutIntervalForRequest = 60.0
|
||||
sessionConfiguration.httpShouldSetCookies = false
|
||||
sessionConfiguration.httpCookieAcceptPolicy = .never
|
||||
sessionConfiguration.httpMaximumConnectionsPerHost = 1
|
||||
sessionConfiguration.httpCookieStorage = nil
|
||||
sessionConfiguration.urlCache = nil
|
||||
|
||||
if let userAgentHeaders = UserAgent.headers() {
|
||||
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
|
||||
}
|
||||
|
||||
let session = URLSession(configuration: sessionConfiguration)
|
||||
caller = NewsBlurAPICaller(transport: session)
|
||||
}
|
||||
|
||||
database = SyncDatabase(databaseFilePath: dataFolder.appending("/DB.sqlite3"))
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func importOPML(for account: Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func addFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> ()) {
|
||||
}
|
||||
|
||||
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func createWebFeed(for account: Account, url: String, name: String?, container: Container, completion: @escaping (Result<WebFeed, Error>) -> ()) {
|
||||
}
|
||||
|
||||
func renameWebFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func addWebFeed(for account: Account, with: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func removeWebFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func moveWebFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func restoreWebFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func restoreFolder(for account: Account, folder: Folder, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
fatalError("markArticles(for:articles:statusKey:flag:) has not been implemented")
|
||||
}
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
credentials = try? account.retrieveCredentials(type: .newsBlur)
|
||||
}
|
||||
|
||||
func accountWillBeDeleted(_ account: Account) {
|
||||
caller.logout() { _ in }
|
||||
}
|
||||
|
||||
class func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> ()) {
|
||||
let caller = NewsBlurAPICaller(transport: transport)
|
||||
caller.credentials = credentials
|
||||
caller.validateCredentials() { result in
|
||||
DispatchQueue.main.async {
|
||||
completion(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func suspendNetwork() {
|
||||
}
|
||||
|
||||
func suspendDatabase() {
|
||||
database.suspend()
|
||||
}
|
||||
|
||||
func resume() {
|
||||
database.resume()
|
||||
}
|
||||
}
|
@ -439,7 +439,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Email" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="S4v-fs-DIO">
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username or Email" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="S4v-fs-DIO">
|
||||
<rect key="frame" x="20" y="11.5" width="334" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" spellCheckingType="no" keyboardType="emailAddress" textContentType="username"/>
|
||||
|
@ -14,7 +14,7 @@ class NewsBlurAccountViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
||||
@IBOutlet weak var cancelBarButtonItem: UIBarButtonItem!
|
||||
@IBOutlet weak var emailTextField: UITextField!
|
||||
@IBOutlet weak var usernameTextField: UITextField!
|
||||
@IBOutlet weak var passwordTextField: UITextField!
|
||||
@IBOutlet weak var showHideButton: UIButton!
|
||||
@IBOutlet weak var actionButton: UIButton!
|
||||
@ -26,19 +26,19 @@ class NewsBlurAccountViewController: UITableViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
activityIndicator.isHidden = true
|
||||
emailTextField.delegate = self
|
||||
usernameTextField.delegate = self
|
||||
passwordTextField.delegate = self
|
||||
|
||||
if let account = account, let credentials = try? account.retrieveCredentials(type: .basic) {
|
||||
actionButton.setTitle(NSLocalizedString("Update Credentials", comment: "Update Credentials"), for: .normal)
|
||||
actionButton.isEnabled = true
|
||||
emailTextField.text = credentials.username
|
||||
usernameTextField.text = credentials.username
|
||||
passwordTextField.text = credentials.secret
|
||||
} else {
|
||||
actionButton.setTitle(NSLocalizedString("Add Account", comment: "Add Account"), for: .normal)
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: emailTextField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: usernameTextField)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: passwordTextField)
|
||||
|
||||
tableView.register(ImageHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader")
|
||||
@ -75,17 +75,19 @@ class NewsBlurAccountViewController: UITableViewController {
|
||||
|
||||
@IBAction func action(_ sender: Any) {
|
||||
|
||||
guard let email = emailTextField.text, let password = passwordTextField.text else {
|
||||
showError(NSLocalizedString("Username & password required.", comment: "Credentials Error"))
|
||||
guard let username = usernameTextField.text else {
|
||||
showError(NSLocalizedString("Username required.", comment: "Credentials Error"))
|
||||
return
|
||||
}
|
||||
|
||||
let password = passwordTextField.text ?? ""
|
||||
|
||||
startAnimatingActivityIndicator()
|
||||
disableNavigation()
|
||||
|
||||
// When you fill in the email address via auto-complete it adds extra whitespace
|
||||
let trimmedEmail = email.trimmingCharacters(in: .whitespaces)
|
||||
let credentials = Credentials(type: .basic, username: trimmedEmail, secret: password)
|
||||
let trimmedUsername = username.trimmingCharacters(in: .whitespaces)
|
||||
let credentials = Credentials(type: .newsBlur, username: trimmedUsername, secret: password)
|
||||
Account.validateCredentials(type: .newsBlur, credentials: credentials) { result in
|
||||
|
||||
self.stopAnimtatingActivityIndicator()
|
||||
@ -124,17 +126,17 @@ class NewsBlurAccountViewController: UITableViewController {
|
||||
self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error"))
|
||||
}
|
||||
} else {
|
||||
self.showError(NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error"))
|
||||
self.showError(NSLocalizedString("Invalid username/password combination.", comment: "Credentials Error"))
|
||||
}
|
||||
case .failure:
|
||||
self.showError(NSLocalizedString("Network error. Try again later.", comment: "Credentials Error"))
|
||||
case .failure(let error):
|
||||
self.showError(error.localizedDescription)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@objc func textDidChange(_ note: Notification) {
|
||||
actionButton.isEnabled = !(emailTextField.text?.isEmpty ?? false) && !(passwordTextField.text?.isEmpty ?? false)
|
||||
actionButton.isEnabled = !(usernameTextField.text?.isEmpty ?? false)
|
||||
}
|
||||
|
||||
private func showError(_ message: String) {
|
||||
|
Loading…
Reference in New Issue
Block a user