diff --git a/Mac/AppAssets.swift b/Mac/AppAssets.swift index c537ee21b..a9d62921f 100644 --- a/Mac/AppAssets.swift +++ b/Mac/AppAssets.swift @@ -40,6 +40,10 @@ struct AppAssets { static var accountFreshRSS: RSImage! = { return RSImage(named: "accountFreshRSS") }() + + static var accountNewsBlur: RSImage! = { + return RSImage(named: "accountNewsBlur") + }() static var articleExtractor: RSImage! = { return RSImage(named: "articleExtractor") @@ -151,6 +155,8 @@ struct AppAssets { return AppAssets.accountFeedWrangler case .freshRSS: return AppAssets.accountFreshRSS + case .newsBlur: + return AppAssets.accountNewsBlur default: return nil } diff --git a/Mac/Preferences/Accounts/AccountsAddViewController.swift b/Mac/Preferences/Accounts/AccountsAddViewController.swift index 4923272be..1207852ce 100644 --- a/Mac/Preferences/Accounts/AccountsAddViewController.swift +++ b/Mac/Preferences/Accounts/AccountsAddViewController.swift @@ -17,7 +17,7 @@ class AccountsAddViewController: NSViewController { private var accountsAddWindowController: NSWindowController? #if DEBUG - private var addableAccountTypes: [AccountType] = [.onMyMac, .cloudKit, .feedbin, .feedly, .feedWrangler, .freshRSS] + private var addableAccountTypes: [AccountType] = [.onMyMac, .cloudKit, .feedbin, .feedly, .feedWrangler, .freshRSS, .newsBlur] #else private var addableAccountTypes: [AccountType] = [.onMyMac, .feedbin, .feedly] #endif @@ -80,6 +80,9 @@ extension AccountsAddViewController: NSTableViewDelegate { case .feedly: cell.accountNameLabel?.stringValue = NSLocalizedString("Feedly", comment: "Feedly") cell.accountImageView?.image = AppAssets.accountFeedly + case .newsBlur: + cell.accountNameLabel?.stringValue = NSLocalizedString("NewsBlur", comment: "NewsBlur") + cell.accountImageView?.image = AppAssets.accountNewsBlur default: break } @@ -127,6 +130,10 @@ extension AccountsAddViewController: NSTableViewDelegate { addAccount.delegate = self addAccount.presentationAnchor = self.view.window! MainThreadOperationQueue.shared.add(addAccount) + case .newsBlur: + let accountsNewsBlurWindowController = AccountsNewsBlurWindowController() + accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!) + accountsAddWindowController = accountsNewsBlurWindowController default: break } diff --git a/Mac/Preferences/Accounts/AccountsNewsBlur.xib b/Mac/Preferences/Accounts/AccountsNewsBlur.xib new file mode 100644 index 000000000..3b6027ed8 --- /dev/null +++ b/Mac/Preferences/Accounts/AccountsNewsBlur.xib @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NSAllRomanInputSourcesLocaleIdentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift new file mode 100644 index 000000000..cae19a31a --- /dev/null +++ b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift @@ -0,0 +1,110 @@ +// +// AccountsNewsBlurWindowController.swift +// NetNewsWire +// +// Created by Anh Quang Do on 2020-03-22. +// Copyright (c) 2020 Ranchero Software. All rights reserved. +// + +import AppKit +import Account +import RSWeb + +class AccountsNewsBlurWindowController: NSWindowController { + @IBOutlet weak var progressIndicator: NSProgressIndicator! + @IBOutlet weak var usernameTextField: NSTextField! + @IBOutlet weak var passwordTextField: NSSecureTextField! + @IBOutlet weak var errorMessageLabel: NSTextField! + @IBOutlet weak var actionButton: NSButton! + + var account: Account? + + private weak var hostWindow: NSWindow? + + convenience init() { + self.init(windowNibName: NSNib.Name("AccountsNewsBlur")) + } + + override func windowDidLoad() { + if let account = account, let credentials = try? account.retrieveCredentials(type: .newsBlurBasic) { + usernameTextField.stringValue = credentials.username + actionButton.title = NSLocalizedString("Update", comment: "Update") + } else { + actionButton.title = NSLocalizedString("Create", comment: "Create") + } + } + + // MARK: API + + func runSheetOnWindow(_ hostWindow: NSWindow, completion: ((NSApplication.ModalResponse) -> Void)? = nil) { + self.hostWindow = hostWindow + hostWindow.beginSheet(window!, completionHandler: completion) + } + + // MARK: Actions + + @IBAction func cancel(_ sender: Any) { + hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel) + } + + @IBAction func action(_ sender: Any) { + self.errorMessageLabel.stringValue = "" + + guard !usernameTextField.stringValue.isEmpty else { + self.errorMessageLabel.stringValue = NSLocalizedString("Username required.", comment: "Credentials Error") + return + } + + actionButton.isEnabled = false + progressIndicator.isHidden = false + progressIndicator.startAnimation(self) + + let credentials = Credentials(type: .newsBlurBasic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue) + Account.validateCredentials(type: .newsBlur, credentials: credentials) { [weak self] result in + + guard let self = self else { return } + + self.actionButton.isEnabled = true + self.progressIndicator.isHidden = true + self.progressIndicator.stopAnimation(self) + + switch result { + case .success(let validatedCredentials): + guard let validatedCredentials = validatedCredentials else { + self.errorMessageLabel.stringValue = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error") + return + } + var newAccount = false + if self.account == nil { + self.account = AccountManager.shared.createAccount(type: .newsBlur) + newAccount = true + } + + do { + try self.account?.removeCredentials(type: .newsBlurBasic) + try self.account?.removeCredentials(type: .newsBlurSessionId) + try self.account?.storeCredentials(credentials) + try self.account?.storeCredentials(validatedCredentials) + if newAccount { + self.account?.refreshAll() { result in + switch result { + case .success: + break + case .failure(let error): + NSApplication.shared.presentError(error) + } + } + } + self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK) + } catch { + self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error") + } + + case .failure: + + self.errorMessageLabel.stringValue = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error") + + } + } + } +} diff --git a/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/Contents.json b/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/Contents.json new file mode 100644 index 000000000..99f78349c --- /dev/null +++ b/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "newsblur-512.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/newsblur-512.png b/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/newsblur-512.png new file mode 100644 index 000000000..5fab67691 Binary files /dev/null and b/Mac/Resources/Assets.xcassets/accountNewsBlur.imageset/newsblur-512.png differ diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 4cdb13a9d..9cc10115d 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; }; + 179DB3CE822BFCC2D774D9F4 /* AccountsNewsBlurWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */; }; 3B3A32A5238B820900314204 /* FeedWranglerAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */; }; 3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */; }; 3B826DCC2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */; }; @@ -665,6 +667,8 @@ B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B2B80779239C4C7300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B528F81E23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; }; + BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; + BDCB516824282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; C5A6ED5223C9AF4300AB6BE2 /* TitleActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5A6ED5123C9AF4300AB6BE2 /* TitleActivityItemSource.swift */; }; C5A6ED6D23C9B0C800AB6BE2 /* UIActivityViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5A6ED6C23C9B0C800AB6BE2 /* UIActivityViewController-Extensions.swift */; }; D553738B20186C20006D8857 /* Article+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D553737C20186C1F006D8857 /* Article+Scriptability.swift */; }; @@ -1255,6 +1259,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsNewsBlurWindowController.swift; sourceTree = ""; }; 3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAccountViewController.swift; sourceTree = ""; }; 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsFeedWrangler.xib; sourceTree = ""; }; 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsFeedWranglerWindowController.swift; sourceTree = ""; }; @@ -1626,6 +1631,7 @@ B24EFD5923310109006C6242 /* WKPreferencesPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKPreferencesPrivate.h; sourceTree = ""; }; B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-AppIcons.swift"; sourceTree = ""; }; B528F81D23333C7E00E735DD /* page.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = page.html; sourceTree = ""; }; + BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsNewsBlur.xib; sourceTree = ""; }; C5A6ED5123C9AF4300AB6BE2 /* TitleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleActivityItemSource.swift; sourceTree = ""; }; C5A6ED6C23C9B0C800AB6BE2 /* UIActivityViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivityViewController-Extensions.swift"; sourceTree = ""; }; D519E74722EE553300923F27 /* NetNewsWire_safariextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_safariextension_target.xcconfig; sourceTree = ""; }; @@ -2630,6 +2636,8 @@ 5144EA4F227B8E4500D19003 /* AccountsFeedbinWindowController.swift */, 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */, 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */, + BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */, + 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */, 55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */, 55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */, 5144EA352279FC3D00D19003 /* AccountsAddLocal.xib */, @@ -3501,6 +3509,7 @@ 65ED4066235DEF6C0081F399 /* TimelineTableView.xib in Resources */, 65ED4067235DEF6C0081F399 /* page.html in Resources */, 65ED4068235DEF6C0081F399 /* MainWindow.storyboard in Resources */, + BDCB516824282C8A00102A80 /* AccountsNewsBlur.xib in Resources */, 3B826DCD2385C89600FC1ADB /* AccountsFeedWrangler.xib in Resources */, 65ED4069235DEF6C0081F399 /* AccountsReaderAPI.xib in Resources */, 65ED406A235DEF6C0081F399 /* newsfoot.js in Resources */, @@ -3593,6 +3602,7 @@ 3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */, 55E15BCB229D65A900D6602A /* AccountsReaderAPI.xib in Resources */, 49F40DF82335B71000552BF4 /* newsfoot.js in Resources */, + BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */, 5103A9982421643300410853 /* blank.html in Resources */, 84BAE64921CEDAF20046DB56 /* CrashReporterWindow.xib in Resources */, 84C9FC8E22629E8F00D921D6 /* Credits.rtf in Resources */, @@ -3909,6 +3919,7 @@ 65ED403E235DEF6C0081F399 /* TimelineCellAppearance.swift in Sources */, 65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */, 65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */, + 179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4226,6 +4237,7 @@ 849A97761ED9EC04007D329B /* TimelineCellAppearance.swift in Sources */, 849A977F1ED9EC42007D329B /* ArticleRenderer.swift in Sources */, 84C9FC7822629E1200D921D6 /* GeneralPrefencesViewController.swift in Sources */, + 179DB3CE822BFCC2D774D9F4 /* AccountsNewsBlurWindowController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iOS/Account/NewsBlurAccountViewController.swift b/iOS/Account/NewsBlurAccountViewController.swift index 8a5cb2ddf..9810f8196 100644 --- a/iOS/Account/NewsBlurAccountViewController.swift +++ b/iOS/Account/NewsBlurAccountViewController.swift @@ -29,7 +29,7 @@ class NewsBlurAccountViewController: UITableViewController { usernameTextField.delegate = self passwordTextField.delegate = self - if let account = account, let credentials = try? account.retrieveCredentials(type: .basic) { + if let account = account, let credentials = try? account.retrieveCredentials(type: .newsBlurBasic) { actionButton.setTitle(NSLocalizedString("Update Credentials", comment: "Update Credentials"), for: .normal) actionButton.isEnabled = true usernameTextField.text = credentials.username @@ -90,7 +90,7 @@ class NewsBlurAccountViewController: UITableViewController { let credentials = Credentials(type: .newsBlurBasic, username: trimmedUsername, secret: password) Account.validateCredentials(type: .newsBlur, credentials: credentials) { result in - self.stopAnimtatingActivityIndicator() + self.stopAnimatingActivityIndicator() self.enableNavigation() switch result { @@ -105,7 +105,7 @@ class NewsBlurAccountViewController: UITableViewController { do { do { - try self.account?.removeCredentials(type: .basic) + try self.account?.removeCredentials(type: .newsBlurBasic) } catch {} try self.account?.storeCredentials(credentials) @@ -158,7 +158,7 @@ class NewsBlurAccountViewController: UITableViewController { activityIndicator.startAnimating() } - private func stopAnimtatingActivityIndicator() { + private func stopAnimatingActivityIndicator() { self.activityIndicator.isHidden = true self.activityIndicator.stopAnimating() }