Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
return true
}
switch account.type {
case .onMyMac, .cloudKit, .feedly:
case .onMyMac, .cloudKit, .feedly, .inkwell:
return true
default:
return false
Expand Down
24 changes: 17 additions & 7 deletions Mac/Preferences/Accounts/AccountsPreferencesViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ extension AccountsPreferencesViewController: NSTableViewDelegate {
cell.textField?.stringValue = account.nameForDisplay
cell.imageView?.image = account.smallIcon?.image

if account.type == .feedbin {
if account.type == .feedbin || account.type == .inkwell {
cell.isImageTemplateCapable = false
}

Expand Down Expand Up @@ -189,7 +189,14 @@ extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelega
let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly)
addAccount.delegate = self
addAccount.presentationAnchor = window
runAwaitingFeedlyLoginAlertModal(forLifetimeOf: addAccount)
runAwaitingOAuthLoginAlertModal(forLifetimeOf: addAccount, accountType: .feedly)
MainThreadOperationQueue.shared.add(addAccount)

case .inkwell:
let addAccount = OAuthAccountAuthorizationOperation(accountType: .inkwell)
addAccount.delegate = self
addAccount.presentationAnchor = window
runAwaitingOAuthLoginAlertModal(forLifetimeOf: addAccount, accountType: .inkwell)
MainThreadOperationQueue.shared.add(addAccount)

case .newsBlur:
Expand All @@ -199,14 +206,17 @@ extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelega
}
}

private func runAwaitingFeedlyLoginAlertModal(forLifetimeOf operation: OAuthAccountAuthorizationOperation) {
private func runAwaitingOAuthLoginAlertModal(forLifetimeOf operation: OAuthAccountAuthorizationOperation, accountType: AccountType) {
let serviceName = accountType.localizedAccountName()
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = NSLocalizedString("Waiting for access to Feedly",
comment: "Alert title when adding a Feedly account and waiting for authorization from the user.")
let messageFormat = NSLocalizedString("Waiting for access to %@",
comment: "Alert title when adding an OAuth account and waiting for authorization from the user.")
alert.messageText = String(format: messageFormat, serviceName)

alert.informativeText = NSLocalizedString("A web browser will open the Feedly login for you to authorize access.",
comment: "Alert informative text when adding a Feedly account and waiting for authorization from the user.")
let informativeFormat = NSLocalizedString("A web browser will open the %@ login for you to authorize access.",
comment: "Alert informative text when adding an OAuth account and waiting for authorization from the user.")
alert.informativeText = String(format: informativeFormat, serviceName)

alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "Cancel"))

Expand Down
4 changes: 2 additions & 2 deletions Mac/Preferences/Accounts/AddAccountsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ enum AddAccountSections: Int, CaseIterable {
return [.cloudKit]
case .web:
if AppDefaults.shared.isDeveloperBuild {
return [.bazQux, .feedbin, .feedly, .inoreader, .newsBlur, .theOldReader].filter({ $0.isDeveloperRestricted == false })
return [.bazQux, .feedbin, .feedly, .inkwell, .inoreader, .newsBlur, .theOldReader].filter({ $0.isDeveloperRestricted == false })
} else {
return [.bazQux, .feedbin, .feedly, .inoreader, .newsBlur, .theOldReader]
return [.bazQux, .feedbin, .feedly, .inkwell, .inoreader, .newsBlur, .theOldReader]
}
case .selfhosted:
return [.freshRSS]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "inkwell_icon_48.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Mac/Resources/NetNewsWire.sdef
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<enumerator name="cloudkit" code="Clkt" description="The iCloud account"/>
<enumerator name="feedly" code="Fdly" description="A Feedly account"/>
<enumerator name="feedbin" code="Fdbn" description="A Feedbin account"/>
<enumerator name="inkwell" code="Mcro" description="An Inkwell account"/>
<enumerator name="newsblur" code="NBlr" description="A Newsblur account"/>
<enumerator name="fresh rss" code="Frsh" description="A Fresh RSS account"/>
<enumerator name="inoreader" code="Inrd" description="An Inoreader account"/>
Expand Down Expand Up @@ -264,4 +265,3 @@
</suite>

</dictionary>

2 changes: 2 additions & 0 deletions Mac/Scripting/Account+Scriptability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ import RSCore
osType = "Fdly"
case .feedbin:
osType = "Fdbn"
case .inkwell:
osType = "Mcro"
case .newsBlur:
osType = "NBlr"
case .freshRSS:
Expand Down
13 changes: 13 additions & 0 deletions Modules/Account/Sources/Account/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ nonisolated public enum AccountType: Int, Codable, Sendable {
case inoreader = 21
case bazQux = 22
case theOldReader = 23
case inkwell = 24

public var isDeveloperRestricted: Bool {
return self == .cloudKit || self == .feedbin || self == .feedly || self == .inoreader
Expand Down Expand Up @@ -271,6 +272,8 @@ public enum FetchType {
self.delegate = FeedbinAccountDelegate(dataFolder: dataFolder, transport: transport)
case .feedly:
self.delegate = FeedlyAccountDelegate(dataFolder: dataFolder, transport: transport, api: FeedlyAccountDelegate.environment)
case .inkwell:
self.delegate = InkwellAccountDelegate(dataFolder: dataFolder, transport: transport)
case .newsBlur:
self.delegate = NewsBlurAccountDelegate(dataFolder: dataFolder, transport: transport)
case .freshRSS:
Expand Down Expand Up @@ -302,6 +305,8 @@ public enum FetchType {
defaultName = NSLocalizedString("Feedbin", comment: "Feedbin")
case .newsBlur:
defaultName = NSLocalizedString("NewsBlur", comment: "NewsBlur")
case .inkwell:
defaultName = NSLocalizedString("Inkwell", comment: "Inkwell")
case .freshRSS:
defaultName = NSLocalizedString("FreshRSS", comment: "FreshRSS")
case .inoreader:
Expand Down Expand Up @@ -383,6 +388,8 @@ public enum FetchType {
return try await NewsBlurAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint)
case .freshRSS, .inoreader, .bazQux, .theOldReader:
return try await ReaderAPIAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint)
case .inkwell:
return try await InkwellAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint)
default:
return nil
}
Expand All @@ -392,6 +399,8 @@ public enum FetchType {
switch type {
case .feedly:
return FeedlyAccountDelegate.environment.oauthAuthorizationClient
case .inkwell:
return .inkwellClient
default:
fatalError("\(type) is not a client for OAuth authorization code granting.")
}
Expand All @@ -402,6 +411,8 @@ public enum FetchType {
switch type {
case .feedly:
grantingType = FeedlyAccountDelegate.self
case .inkwell:
grantingType = InkwellAccountDelegate.self
default:
fatalError("\(type) does not support OAuth authorization code granting.")
}
Expand All @@ -419,6 +430,8 @@ public enum FetchType {
switch accountType {
case .feedly:
grantingType = FeedlyAccountDelegate.self
case .inkwell:
grantingType = InkwellAccountDelegate.self
default:
fatalError("\(accountType) does not support OAuth authorization code granting.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError, Sendable {
case duplicateAccount

public var errorDescription: String? {
return NSLocalizedString("There is already a Feedly account with that username created.", comment: "Duplicate Error")
return NSLocalizedString("There is already an account with that username created.", comment: "Duplicate Error")
}
}

Expand Down Expand Up @@ -196,13 +196,13 @@ private extension OAuthAccountAuthorizationOperation {

func saveAccount(for grant: OAuthAuthorizationGrant) {
Self.logger.debug("OAuthAccountAuthorizationOperation: saveAccount")
guard !AccountManager.shared.duplicateServiceAccount(type: .feedly, username: grant.accessToken.username) else {
guard !AccountManager.shared.duplicateServiceAccount(type: accountType, username: grant.accessToken.username) else {
self.error = OAuthAccountAuthorizationOperationError.duplicateAccount
didComplete()
return
}

let account = AccountManager.shared.createAccount(type: .feedly)
let account = AccountManager.shared.createAccount(type: accountType)
do {

// Store the refresh token first because it sends this token to the account delegate.
Expand All @@ -221,4 +221,3 @@ private extension OAuthAccountAuthorizationOperation {
didComplete()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@ nonisolated extension OAuthAuthorizationClient {
state: nil,
secret: "4ZfZ5DvqmJ8vKgMj")
}

static var inkwellClient: OAuthAuthorizationClient {
return OAuthAuthorizationClient(id: "https://netnewswire.com/",
redirectUri: "netnewswire://auth/inkwell",
state: nil,
secret: "")
}
}
14 changes: 14 additions & 0 deletions Modules/Account/Sources/Account/Inkwell/Inkwell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Inkwell.swift
// Account
//
// Created by Manton Reece on 3/11/26.
//

import Foundation
import os.log

struct Inkwell {
// Convention with this logger is to put "Inkwell: " at the beginning of each message.
static let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Inkwell")
}
Loading