validate Feedbin account credentials and add Feedbin account
This commit is contained in:
parent
296ebb82bd
commit
5a852c1615
|
@ -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)
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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 account’s init method.
|
||||
|
|
|
@ -12,5 +12,6 @@ final class AccountSettings: Codable {
|
|||
|
||||
var name: String?
|
||||
var isActive: Bool = true
|
||||
var username: String?
|
||||
|
||||
}
|
||||
|
|
|
@ -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)!
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue