validate Feedbin account credentials and add Feedbin account

This commit is contained in:
Maurice Parker 2019-05-02 18:17:52 -05:00
parent 296ebb82bd
commit 5a852c1615
13 changed files with 446 additions and 9 deletions

View File

@ -96,13 +96,24 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
return _idToFeedDictionary
}
var username: String? {
get {
return settings.username
}
set {
if newValue != settings.username {
settings.username = newValue
settingsDirty = true
}
}
}
private var fetchingAllUnreadCounts = false
var isUnreadCountsInitialized = false
let dataFolder: String
let database: ArticlesDatabase
let delegate: AccountDelegate
var username: String?
static let saveQueue = CoalescingQueue(name: "Account Save Queue", interval: 1.0)
private var unreadCounts = [String: Int]() // [feedID: Int]
@ -168,9 +179,14 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
init?(dataFolder: String, type: AccountType, accountID: String) {
// TODO: support various syncing systems.
precondition(type == .onMyMac)
self.delegate = LocalAccountDelegate()
switch type {
case .onMyMac:
self.delegate = LocalAccountDelegate()
case .feedbin:
self.delegate = FeedbinAccountDelegate()
default:
fatalError("Only Local and Feedbin accounts are supported")
}
self.accountID = accountID
self.type = type
@ -220,10 +236,27 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
self.delegate.accountDidInitialize(self)
startingUp = false
}
// MARK: - API
public func storeCredentials(username: String, password: String) {
self.username = username
// self.password = password
}
public static func validateCredentials(type: AccountType, username: String, password: String, completionHandler handler: @escaping ((Bool) -> ())) {
switch type {
case .onMyMac:
LocalAccountDelegate.validateCredentials(username: username, password: password, completionHandler: handler)
case .feedbin:
FeedbinAccountDelegate.validateCredentials(username: username, password: password, completionHandler: handler)
default:
break
}
}
public func refreshAll() {
delegate.refreshAll(for: self)

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.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 */; };
@ -83,6 +85,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = "<group>"; };
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.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>"; };
@ -177,6 +181,8 @@
84245C7D1FDDD2580074AFBB /* Feedbin */ = {
isa = PBXGroup;
children = (
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */,
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */,
84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */,
84CAD7151FDF2E22000F0755 /* FeedbinArticle.swift */,
84D096202174169100D77525 /* FeedbinArticleIDArray.swift */,
@ -418,12 +424,14 @@
84C3654A1F899F3B001EC85C /* CombinedRefreshProgress.swift in Sources */,
8469F81C1F6DD15E0084783E /* Account.swift in Sources */,
84D096212174169100D77525 /* FeedbinArticleIDArray.swift in Sources */,
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */,
846E77451F6EF9B900A165E2 /* Container.swift in Sources */,
84F73CF1202788D90000BCEF /* ArticleFetcher.swift in Sources */,
841974251F6DDCE4006346C4 /* AccountDelegate.swift in Sources */,
846E77541F6F00E300A165E2 /* AccountManager.swift in Sources */,
844B297D2106C7EC004020B3 /* Feed.swift in Sources */,
84B2D4D02238CD8A00498ADA /* FeedMetadata.swift in Sources */,
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */,
84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */,
846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */,
84D09623217418DC00D77525 /* FeedbinTagging.swift in Sources */,

View File

@ -16,6 +16,8 @@ public protocol AccountDelegate {
var refreshProgress: DownloadProgress { get }
static func validateCredentials(username: String, password: String, completionHandler handler: @escaping ((Bool) -> ()))
func refreshAll(for: Account)
// Called at the end of accounts init method.

View File

@ -12,5 +12,6 @@ final class AccountSettings: Codable {
var name: String?
var isActive: Bool = true
var username: String?
}

View File

@ -0,0 +1,55 @@
//
// FeedbinAPICaller.swift
// Account
//
// Created by Maurice Parker on 5/2/19.
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import RSWeb
final class FeedbinAPICaller: NSObject {
private static let feedbinBaseURL = "https://api.feedbin.com/v2/"
private var session: URLSession!
override init() {
super.init()
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
sessionConfiguration.timeoutIntervalForRequest = 60.0
sessionConfiguration.httpShouldSetCookies = false
sessionConfiguration.httpCookieAcceptPolicy = .never
sessionConfiguration.httpMaximumConnectionsPerHost = 2
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
session = URLSession(configuration: sessionConfiguration)
}
func validateCredentials(username: String, password: String, completionHandler handler: @escaping APIResultBlock) {
let request = URLRequest(url: urlFromRelativePath("authentication.json"), username: username, password: password)
let call = APICall(session: session, request: request)
call.execute(completionHandler: handler)
}
}
// MARK: Private
private extension FeedbinAPICaller {
func urlFromRelativePath(_ path: String) -> URL {
let fullPath = "\(FeedbinAPICaller.feedbinBaseURL)\(path)"
return URL(string: fullPath)!
}
}

View File

@ -0,0 +1,54 @@
//
// FeedbinAccountDelegate.swift
// Account
//
// Created by Maurice Parker on 5/2/19.
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import RSWeb
final class FeedbinAccountDelegate: AccountDelegate {
let supportsSubFolders = false
private let caller = FeedbinAPICaller()
var refreshProgress: DownloadProgress {
return DownloadProgress(numberOfTasks: 0)
}
static func validateCredentials(username: String, password: String, completionHandler handler: @escaping ((Bool) -> ())) {
let caller = FeedbinAPICaller()
caller.validateCredentials(username: username, password: password) { result in
if result.statusCode == 200 {
handler(true)
} else {
handler(false)
}
}
}
func refreshAll(for account: Account) {
}
func accountDidInitialize(_ account: Account) {
}
// MARK: Disk
func update(account: Account, withUserInfo: NSDictionary?) {
}
func userInfo(for: Account) -> NSDictionary? {
return nil
}
}

View File

@ -18,6 +18,10 @@ final class LocalAccountDelegate: AccountDelegate {
return refresher.progress
}
static func validateCredentials(username: String, password: String, completionHandler handler: ((Bool) -> ())) {
return handler(false)
}
func refreshAll(for account: Account) {
refresher.refreshFeeds(account.flattenedFeeds())
@ -29,12 +33,9 @@ final class LocalAccountDelegate: AccountDelegate {
// MARK: Disk
func update(account: Account, withUserInfo: NSDictionary?) {
}
func userInfo(for: Account) -> NSDictionary? {
return nil
}
}

View File

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="AccountsAddFeedbinWindowController" customModule="NetNewsWire" customModuleProvider="target">
<connections>
<outlet property="createButton" destination="9mz-D9-krh" id="p7i-JM-G69"/>
<outlet property="errorMessageLabel" destination="byK-Sd-r7F" id="8zt-9d-dWQ"/>
<outlet property="passwordTextField" destination="JSa-LY-zNQ" id="5cF-bM-CJE"/>
<outlet property="progressIndicator" destination="B0W-bh-Evv" id="Tiq-gx-s3F"/>
<outlet property="usernameTextField" destination="78p-Cf-f55" id="Gg5-Ce-RJv"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="433" height="249"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="433" height="249"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="horizontal" alignment="bottom" spacing="19" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7Ht-Fn-0Ya">
<rect key="frame" x="134" y="190" width="166" height="39"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Ssh-Dh-xbg">
<rect key="frame" x="0.0" y="0.0" width="36" height="36"/>
<constraints>
<constraint firstAttribute="height" constant="36" id="Ern-Kk-8LX"/>
<constraint firstAttribute="width" constant="36" id="PLS-68-NMc"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="accountFeedbin" id="y38-YL-woC"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lti-yM-8LV">
<rect key="frame" x="53" y="0.0" width="115" height="39"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Feedbin" id="ras-dj-nP8">
<font key="font" metaFont="system" size="32"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
<gridView xPlacement="trailing" yPlacement="center" rowAlignment="none" rowSpacing="12" columnSpacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="zBB-JH-huI">
<rect key="frame" x="79" y="61" width="276" height="97"/>
<rows>
<gridRow id="DRl-lC-vUc"/>
<gridRow id="eW8-uH-txq"/>
<gridRow id="DbI-7g-Xme"/>
</rows>
<columns>
<gridColumn id="fCQ-jY-Mts"/>
<gridColumn xPlacement="leading" id="7CY-bX-6x4"/>
</columns>
<gridCells>
<gridCell row="DRl-lC-vUc" column="fCQ-jY-Mts" id="4DI-01-jGD">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Zy6-9c-8TI">
<rect key="frame" x="23" y="78" width="41" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Email:" id="DqN-SV-v35">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="DRl-lC-vUc" column="7CY-bX-6x4" id="Z0b-qS-MUJ">
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="78p-Cf-f55">
<rect key="frame" x="76" y="75" width="200" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="Qin-jm-4zt"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="fCk-Tf-q01">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="7Z4-KY-ChP"/>
</connections>
</textField>
</gridCell>
<gridCell row="eW8-uH-txq" column="fCQ-jY-Mts" id="Hqa-3w-cQv">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wEx-TM-rPM">
<rect key="frame" x="-2" y="44" width="66" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Password:" id="7g8-Kk-ISg">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="eW8-uH-txq" column="7CY-bX-6x4" id="m16-3v-9pf">
<secureTextField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JSa-LY-zNQ">
<rect key="frame" x="76" y="41" width="200" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="eal-wa-1nU"/>
</constraints>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="trK-OG-tBe">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="jAp-eC-dOn"/>
</connections>
</secureTextField>
</gridCell>
<gridCell row="DbI-7g-Xme" column="fCQ-jY-Mts" headOfMergedCell="xX0-vn-AId" xPlacement="leading" id="xX0-vn-AId">
<textField key="contentView" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="byK-Sd-r7F">
<rect key="frame" x="-2" y="6" width="104" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" id="0yh-Ab-UTX">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="DbI-7g-Xme" column="7CY-bX-6x4" headOfMergedCell="xX0-vn-AId" id="hk5-St-E4y"/>
</gridCells>
</gridView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9mz-D9-krh">
<rect key="frame" x="338" y="13" width="81" height="32"/>
<buttonCell key="cell" type="push" title="Create" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="IMO-YT-k9Z">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="create:" target="-2" id="jfu-Va-dnt"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XAM-Hb-0Hw">
<rect key="frame" x="256" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ufs-ar-BAY">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancel:" target="-2" id="WAD-ES-hpq"/>
</connections>
</button>
<progressIndicator hidden="YES" wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="B0W-bh-Evv">
<rect key="frame" x="209" y="166" width="16" height="16"/>
</progressIndicator>
</subviews>
<constraints>
<constraint firstItem="9mz-D9-krh" firstAttribute="leading" secondItem="XAM-Hb-0Hw" secondAttribute="trailing" constant="12" symbolic="YES" id="CC8-HR-FDy"/>
<constraint firstItem="XAM-Hb-0Hw" firstAttribute="centerY" secondItem="9mz-D9-krh" secondAttribute="centerY" id="M2M-fb-kfR"/>
<constraint firstAttribute="bottom" secondItem="9mz-D9-krh" secondAttribute="bottom" constant="20" id="PK2-Ye-400"/>
<constraint firstItem="zBB-JH-huI" firstAttribute="top" secondItem="B0W-bh-Evv" secondAttribute="bottom" constant="8" id="V7z-a7-OOG"/>
<constraint firstItem="9mz-D9-krh" firstAttribute="top" secondItem="zBB-JH-huI" secondAttribute="bottom" constant="20" symbolic="YES" id="Wu3-hp-Vzh"/>
<constraint firstItem="zBB-JH-huI" firstAttribute="centerX" secondItem="se5-gp-TjO" secondAttribute="centerX" id="aFI-4s-mMv"/>
<constraint firstAttribute="trailing" secondItem="9mz-D9-krh" secondAttribute="trailing" constant="20" id="fVQ-zN-rKd"/>
<constraint firstItem="B0W-bh-Evv" firstAttribute="top" secondItem="lti-yM-8LV" secondAttribute="bottom" constant="8" id="gq2-tB-pXH"/>
<constraint firstItem="7Ht-Fn-0Ya" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="20" id="jlY-Jg-KJR"/>
<constraint firstItem="B0W-bh-Evv" firstAttribute="centerX" secondItem="se5-gp-TjO" secondAttribute="centerX" id="lrN-Gd-iXd"/>
<constraint firstItem="7Ht-Fn-0Ya" firstAttribute="centerX" secondItem="se5-gp-TjO" secondAttribute="centerX" id="tAZ-Te-w3H"/>
</constraints>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="116.5" y="136.5"/>
</window>
</objects>
<resources>
<image name="accountFeedbin" width="120" height="102"/>
</resources>
</document>

View File

@ -0,0 +1,80 @@
//
// AccountsAddFeedbinWindowController.swift
// NetNewsWire
//
// Created by Maurice Parker on 5/2/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import AppKit
import Account
class AccountsAddFeedbinWindowController: NSWindowController, NSTextFieldDelegate {
@IBOutlet weak var progressIndicator: NSProgressIndicator!
@IBOutlet weak var usernameTextField: NSTextField!
@IBOutlet weak var passwordTextField: NSSecureTextField!
@IBOutlet weak var errorMessageLabel: NSTextField!
@IBOutlet weak var createButton: NSButton!
private weak var hostWindow: NSWindow?
convenience init() {
self.init(windowNibName: NSNib.Name("AccountsAddFeedbin"))
}
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow, completionHandler handler: ((NSApplication.ModalResponse) -> Void)? = nil) {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!, completionHandler: handler)
}
// MARK: NSTextFieldDelegate
func controlTextDidEndEditing(_ obj: Notification) {
if !usernameTextField.stringValue.isEmpty {
createButton.isEnabled = true
} else {
createButton.isEnabled = false
}
}
// MARK: Actions
@IBAction func cancel(_ sender: Any) {
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel)
}
@IBAction func create(_ sender: Any) {
createButton.isEnabled = false
progressIndicator.isHidden = false
progressIndicator.startAnimation(self)
Account.validateCredentials(type: .feedbin, username: usernameTextField.stringValue, password: passwordTextField.stringValue) { [weak self] result in
guard let self = self else { return }
self.createButton.isEnabled = true
self.progressIndicator.isHidden = true
self.progressIndicator.stopAnimation(self)
if result {
let account = AccountManager.shared.createAccount(type: .feedbin)
account.storeCredentials(username: self.usernameTextField.stringValue, password: self.passwordTextField.stringValue)
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} else {
self.errorMessageLabel.stringValue = NSLocalizedString("Unable to verify credentials", comment: "Credentials Error")
}
}
}
}

View File

@ -82,6 +82,10 @@ extension AccountsAddViewController: NSTableViewDelegate {
let accountsAddLocalWindowController = AccountsAddLocalWindowController()
accountsAddLocalWindowController.runSheetOnWindow(self.view.window!)
accountsAddWindowController = accountsAddLocalWindowController
case 1:
let accountsAddLocalWindowController = AccountsAddFeedbinWindowController()
accountsAddLocalWindowController.runSheetOnWindow(self.view.window!)
accountsAddWindowController = accountsAddLocalWindowController
default:
break
}

View File

@ -26,6 +26,8 @@
5144EA43227A380F00D19003 /* ExportOPMLWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */; };
5144EA46227A5A8700D19003 /* AccountsDeleteWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA44227A5A8700D19003 /* AccountsDeleteWindowController.swift */; };
5144EA47227A5A8700D19003 /* AccountsDelete.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA45227A5A8700D19003 /* AccountsDelete.xib */; };
5144EA51227B8E4500D19003 /* AccountsAddFeedbinWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4F227B8E4500D19003 /* AccountsAddFeedbinWindowController.swift */; };
5144EA52227B8E4500D19003 /* AccountsAddFeedbin.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA50227B8E4500D19003 /* AccountsAddFeedbin.xib */; };
5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; };
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; };
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; };
@ -654,6 +656,8 @@
5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportOPMLWindowController.swift; sourceTree = "<group>"; };
5144EA44227A5A8700D19003 /* AccountsDeleteWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsDeleteWindowController.swift; sourceTree = "<group>"; };
5144EA45227A5A8700D19003 /* AccountsDelete.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsDelete.xib; sourceTree = "<group>"; };
5144EA4F227B8E4500D19003 /* AccountsAddFeedbinWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddFeedbinWindowController.swift; sourceTree = "<group>"; };
5144EA50227B8E4500D19003 /* AccountsAddFeedbin.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAddFeedbin.xib; sourceTree = "<group>"; };
5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = "<group>"; };
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = "<group>"; };
5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = "<group>"; };
@ -1598,6 +1602,8 @@
51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */,
84C9FC7422629E1200D921D6 /* AccountsDetail.xib */,
5144EA2E2279FAB600D19003 /* AccountsDetailViewController.swift */,
5144EA50227B8E4500D19003 /* AccountsAddFeedbin.xib */,
5144EA4F227B8E4500D19003 /* AccountsAddFeedbinWindowController.swift */,
5144EA352279FC3D00D19003 /* AccountsAddLocal.xib */,
5144EA372279FC6200D19003 /* AccountsAddLocalWindowController.swift */,
5144EA45227A5A8700D19003 /* AccountsDelete.xib */,
@ -2209,6 +2215,7 @@
848362FD2262A30800DA1D35 /* styleSheet.css in Resources */,
8483630B2262A3F000DA1D35 /* RenameSheet.xib in Resources */,
848363052262A3CC00DA1D35 /* AddFolderSheet.xib in Resources */,
5144EA52227B8E4500D19003 /* AccountsAddFeedbin.xib in Resources */,
8405DDA222168920008CE1BF /* TimelineTableView.xib in Resources */,
8483630E2262A3FE00DA1D35 /* MainWindow.storyboard in Resources */,
84BAE64921CEDAF20046DB56 /* CrashReporterWindow.xib in Resources */,
@ -2432,6 +2439,7 @@
8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */,
5144EA382279FC6200D19003 /* AccountsAddLocalWindowController.swift in Sources */,
84AD1EAA2031617300BC20B7 /* FolderPasteboardWriter.swift in Sources */,
5144EA51227B8E4500D19003 /* AccountsAddFeedbinWindowController.swift in Sources */,
84AD1EBC2032AF5C00BC20B7 /* SidebarOutlineDataSource.swift in Sources */,
845A29241FC9255E007B49E3 /* SidebarCellAppearance.swift in Sources */,
84F3EE1620DEC97E003FADEB /* FeedFinder.swift in Sources */,

@ -1 +1 @@
Subproject commit ac59e34818d4a0c2d3e510f0dad4adf33cf43ce7
Subproject commit 6c9cab0e15bc4299e84866783fd59268e72d1771

@ -1 +1 @@
Subproject commit 68704373aa0c34c01f470bb7373da1f4ae7f5d57
Subproject commit c7c235e45bc77930688af875f44ada769c89f1bf