diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index f44e018df..40ed20899 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -369,12 +369,12 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, switch type { case .feedbin: FeedbinAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion) - case .freshRSS: - 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) + case .freshRSS, .inoreader, .bazQux, .theOldReader: + ReaderAPIAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint, completion: completion) default: break } diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index 1168a143e..38b4290e5 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -21,11 +21,7 @@ public enum ReaderAPIAccountDelegateError: String, Error { final class ReaderAPIAccountDelegate: AccountDelegate { - private var variant: ReaderAPIVariant { - didSet { - caller.variant = variant - } - } + private let variant: ReaderAPIVariant private let database: SyncDatabase @@ -61,11 +57,8 @@ final class ReaderAPIAccountDelegate: AccountDelegate { database = SyncDatabase(databaseFilePath: databaseFilePath) if transport != nil { - caller = ReaderAPICaller(transport: transport!) - } else { - let sessionConfiguration = URLSessionConfiguration.default sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData sessionConfiguration.timeoutIntervalForRequest = 60.0 @@ -80,9 +73,9 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } caller = ReaderAPICaller(transport: URLSession(configuration: sessionConfiguration)) - } + caller.variant = variant self.variant = variant } @@ -1022,7 +1015,7 @@ private extension ReaderAPIAccountDelegate { } - func syncArticleReadState(account: Account, articleIDs: [Int]?) { + func syncArticleReadState(account: Account, articleIDs: [String]?) { guard let articleIDs = articleIDs else { return } @@ -1030,9 +1023,7 @@ private extension ReaderAPIAccountDelegate { database.selectPendingReadStatusArticleIDs() { result in func process(_ pendingArticleIDs: Set) { - - let readerUnreadArticleIDs = Set(articleIDs.map { String($0) } ) - let updatableReaderUnreadArticleIDs = readerUnreadArticleIDs.subtracting(pendingArticleIDs) + let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) account.fetchUnreadArticleIDs { articleIDsResult in guard let currentUnreadArticleIDs = try? articleIDsResult.get() else { @@ -1047,7 +1038,6 @@ private extension ReaderAPIAccountDelegate { let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableReaderUnreadArticleIDs) account.markAsRead(deltaReadArticleIDs) } - } switch result { @@ -1061,7 +1051,7 @@ private extension ReaderAPIAccountDelegate { } - func syncArticleStarredState(account: Account, articleIDs: [Int]?) { + func syncArticleStarredState(account: Account, articleIDs: [String]?) { guard let articleIDs = articleIDs else { return } @@ -1069,9 +1059,7 @@ private extension ReaderAPIAccountDelegate { database.selectPendingStarredStatusArticleIDs() { result in func process(_ pendingArticleIDs: Set) { - - let readerStarredArticleIDs = Set(articleIDs.map { String($0) } ) - let updatableReaderUnreadArticleIDs = readerStarredArticleIDs.subtracting(pendingArticleIDs) + let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) account.fetchStarredArticleIDs { articleIDsResult in guard let currentStarredArticleIDs = try? articleIDsResult.get() else { @@ -1086,7 +1074,6 @@ private extension ReaderAPIAccountDelegate { let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableReaderUnreadArticleIDs) account.markAsUnstarred(deltaUnstarredArticleIDs) } - } switch result { diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift b/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift index 223598ba4..0de8a21e1 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift @@ -64,17 +64,13 @@ final class ReaderAPICaller: NSObject { private var APIBaseURL: URL? { get { switch variant { - case .inoreader: - return URL(string: "https://www.inoreader.com") - case .bazQux: - return URL(string: "https://bazqux.com") - case .theOldReader: - return URL(string: "https://theoldreader.com") case .generic: guard let accountMetadata = accountMetadata else { return nil } return accountMetadata.endpointURL + default: + return URL(string: variant.host) } } } @@ -685,9 +681,13 @@ final class ReaderAPICaller: NSObject { // Get ids from above into hex representation of value let idsToFetch = entries.itemRefs.map({ (reference) -> String in - let idValue = Int(reference.itemId)! - let idHexString = String(idValue, radix: 16, uppercase: false) - return "i=\(idHexString)" + if self.variant == .theOldReader { + return "i=\(reference.itemId)" + } else { + let idValue = Int(reference.itemId)! + let idHexString = String(idValue, radix: 16, uppercase: false) + return "i=\(idHexString)" + } }).joined(separator:"&") let postData = "T=\(token)&output=json&\(idsToFetch)".data(using: String.Encoding.utf8) @@ -749,7 +749,7 @@ final class ReaderAPICaller: NSObject { } - func retrieveUnreadEntries(completion: @escaping (Result<[Int]?, Error>) -> Void) { + func retrieveUnreadEntries(completion: @escaping (Result<[String]?, Error>) -> Void) { guard let baseURL = APIBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) @@ -783,7 +783,7 @@ final class ReaderAPICaller: NSObject { return } - let itemIds = itemRefs.map{ Int($0.itemId)! } + let itemIds = itemRefs.map { $0.itemId } self.storeConditionalGet(key: ConditionalGetKeys.unreadEntries, headers: response.allHeaderFields) completion(.success(itemIds)) @@ -853,7 +853,7 @@ final class ReaderAPICaller: NSObject { updateStateToEntries(entries: entries, state: .starred, add: false, completion: completion) } - func retrieveStarredEntries(completion: @escaping (Result<[Int]?, Error>) -> Void) { + func retrieveStarredEntries(completion: @escaping (Result<[String]?, Error>) -> Void) { guard let baseURL = APIBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return @@ -879,14 +879,12 @@ final class ReaderAPICaller: NSObject { switch result { case .success(let (response, unreadEntries)): - guard let itemRefs = unreadEntries?.itemRefs else { completion(.success([])) return } - let itemIds = itemRefs.map{ Int($0.itemId)! } - + let itemIds = itemRefs.map { $0.itemId } self.storeConditionalGet(key: ConditionalGetKeys.starredEntries, headers: response.allHeaderFields) completion(.success(itemIds)) case .failure(let error): diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIVariant.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIVariant.swift index 61bb03980..07c9a2883 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIVariant.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIVariant.swift @@ -7,9 +7,23 @@ import Foundation -enum ReaderAPIVariant { +public enum ReaderAPIVariant { case generic case inoreader case bazQux case theOldReader + + public var host: String { + switch self { + case .inoreader: + return "https://www.inoreader.com" + case .bazQux: + return "https://bazqux.com" + case .theOldReader: + return "https://theoldreader.com" + default: + return "" + } + } + } diff --git a/Mac/Preferences/Accounts/AccountsReaderAPI.xib b/Mac/Preferences/Accounts/AccountsReaderAPI.xib index eccaed97a..b49e8911c 100644 --- a/Mac/Preferences/Accounts/AccountsReaderAPI.xib +++ b/Mac/Preferences/Accounts/AccountsReaderAPI.xib @@ -1,15 +1,18 @@ - + - + + + + @@ -24,13 +27,13 @@ - + - + @@ -41,7 +44,7 @@ - + @@ -59,7 +62,7 @@ - + @@ -76,7 +79,7 @@ - + @@ -86,7 +89,7 @@ - + @@ -99,7 +102,7 @@ - + @@ -109,7 +112,7 @@ - + @@ -125,7 +128,7 @@ - + @@ -135,7 +138,7 @@ - + @@ -149,7 +152,7 @@ - + @@ -160,7 +163,7 @@ diff --git a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift index 2eeeff8c7..35ce1c4c6 100644 --- a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift +++ b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift @@ -16,6 +16,7 @@ class AccountsReaderAPIWindowController: NSWindowController { @IBOutlet weak var titleImageView: NSImageView! @IBOutlet weak var titleLabel: NSTextField! + @IBOutlet weak var gridView: NSGridView! @IBOutlet weak var progressIndicator: NSProgressIndicator! @IBOutlet weak var usernameTextField: NSTextField! @IBOutlet weak var apiURLTextField: NSTextField! @@ -41,12 +42,15 @@ class AccountsReaderAPIWindowController: NSWindowController { case .inoreader: titleImageView.image = AppAssets.accountInoreader titleLabel.stringValue = NSLocalizedString("InoReader", comment: "InoReader") + gridView.row(at: 2).isHidden = true case .bazQux: titleImageView.image = AppAssets.accountBazQux titleLabel.stringValue = NSLocalizedString("BazQux", comment: "BazQux") + gridView.row(at: 2).isHidden = true case .theOldReader: titleImageView.image = AppAssets.accountTheOldReader titleLabel.stringValue = NSLocalizedString("The Old Reader", comment: "The Old Reader") + gridView.row(at: 2).isHidden = true default: break } @@ -75,25 +79,43 @@ class AccountsReaderAPIWindowController: NSWindowController { } @IBAction func action(_ sender: Any) { - self.errorMessageLabel.stringValue = "" - guard !usernameTextField.stringValue.isEmpty && !passwordTextField.stringValue.isEmpty && !apiURLTextField.stringValue.isEmpty else { + guard !usernameTextField.stringValue.isEmpty && !passwordTextField.stringValue.isEmpty else { self.errorMessageLabel.stringValue = NSLocalizedString("Username, password & API URL are required.", comment: "Credentials Error") return } + guard let accountType = accountType, !(accountType == .freshRSS && apiURLTextField.stringValue.isEmpty) else { + self.errorMessageLabel.stringValue = NSLocalizedString("Username, password & API URL are required.", comment: "Credentials Error") + return + } + + let apiURL: URL + switch accountType { + case .freshRSS: + guard let inputURL = URL(string: apiURLTextField.stringValue) else { + self.errorMessageLabel.stringValue = NSLocalizedString("Invalid API URL.", comment: "Invalid API URL") + return + } + apiURL = inputURL + case .inoreader: + apiURL = URL(string: ReaderAPIVariant.inoreader.host)! + case .bazQux: + apiURL = URL(string: ReaderAPIVariant.bazQux.host)! + case .theOldReader: + apiURL = URL(string: ReaderAPIVariant.theOldReader.host)! + default: + self.errorMessageLabel.stringValue = NSLocalizedString("Unrecognized account type.", comment: "Bad account type") + return + } + actionButton.isEnabled = false progressIndicator.isHidden = false progressIndicator.startAnimation(self) - guard let apiURL = URL(string: apiURLTextField.stringValue) else { - self.errorMessageLabel.stringValue = NSLocalizedString("Invalid API URL.", comment: "Credentials Error") - return - } - let credentials = Credentials(type: .readerBasic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue) - Account.validateCredentials(type: accountType!, credentials: credentials, endpoint: apiURL) { [weak self] result in + Account.validateCredentials(type: accountType, credentials: credentials, endpoint: apiURL) { [weak self] result in guard let self = self else { return }