mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-10 00:50:55 +01:00
Merge branch 'mac-release'
This commit is contained in:
commit
6b2ecdaca0
@ -16,7 +16,6 @@
|
|||||||
5133230A2281082F00C30F19 /* subscriptions_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 513323092281082F00C30F19 /* subscriptions_initial.json */; };
|
5133230A2281082F00C30F19 /* subscriptions_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 513323092281082F00C30F19 /* subscriptions_initial.json */; };
|
||||||
5133230C2281088A00C30F19 /* subscriptions_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230B2281088A00C30F19 /* subscriptions_add.json */; };
|
5133230C2281088A00C30F19 /* subscriptions_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230B2281088A00C30F19 /* subscriptions_add.json */; };
|
||||||
5133230E2281089500C30F19 /* icons.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230D2281089500C30F19 /* icons.json */; };
|
5133230E2281089500C30F19 /* icons.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230D2281089500C30F19 /* icons.json */; };
|
||||||
5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133230F22810E5700C30F19 /* FeedbinIcon.swift */; };
|
|
||||||
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
|
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
|
||||||
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; };
|
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; };
|
||||||
5154367B228EEB28005E1CDF /* FeedbinImportResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */; };
|
5154367B228EEB28005E1CDF /* FeedbinImportResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */; };
|
||||||
@ -214,7 +213,6 @@
|
|||||||
513323092281082F00C30F19 /* subscriptions_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_initial.json; sourceTree = "<group>"; };
|
513323092281082F00C30F19 /* subscriptions_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_initial.json; sourceTree = "<group>"; };
|
||||||
5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = "<group>"; };
|
5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = "<group>"; };
|
||||||
5133230D2281089500C30F19 /* icons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = icons.json; sourceTree = "<group>"; };
|
5133230D2281089500C30F19 /* icons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = icons.json; sourceTree = "<group>"; };
|
||||||
5133230F22810E5700C30F19 /* FeedbinIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinIcon.swift; sourceTree = "<group>"; };
|
|
||||||
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = "<group>"; };
|
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>"; };
|
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = "<group>"; };
|
||||||
5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinImportResult.swift; sourceTree = "<group>"; };
|
5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinImportResult.swift; sourceTree = "<group>"; };
|
||||||
@ -492,7 +490,6 @@
|
|||||||
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */,
|
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */,
|
||||||
51E490352288C37100C791F0 /* FeedbinDate.swift */,
|
51E490352288C37100C791F0 /* FeedbinDate.swift */,
|
||||||
84CAD7151FDF2E22000F0755 /* FeedbinEntry.swift */,
|
84CAD7151FDF2E22000F0755 /* FeedbinEntry.swift */,
|
||||||
5133230F22810E5700C30F19 /* FeedbinIcon.swift */,
|
|
||||||
5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */,
|
5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */,
|
||||||
51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */,
|
51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */,
|
||||||
84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */,
|
84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */,
|
||||||
@ -956,7 +953,6 @@
|
|||||||
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */,
|
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */,
|
||||||
84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */,
|
84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */,
|
||||||
9E510D6E234F16A8002E6F1A /* FeedlyAddFeedRequest.swift in Sources */,
|
9E510D6E234F16A8002E6F1A /* FeedlyAddFeedRequest.swift in Sources */,
|
||||||
5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */,
|
|
||||||
846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */,
|
846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */,
|
||||||
55203300229D5D5A009559E0 /* ReaderAPICaller.swift in Sources */,
|
55203300229D5D5A009559E0 /* ReaderAPICaller.swift in Sources */,
|
||||||
9E1D154F233371DD00F4944C /* FeedlyGetCollectionsOperation.swift in Sources */,
|
9E1D154F233371DD00F4944C /* FeedlyGetCollectionsOperation.swift in Sources */,
|
||||||
|
@ -26,7 +26,6 @@ final class FeedbinAPICaller: NSObject {
|
|||||||
static let subscriptions = "subscriptions"
|
static let subscriptions = "subscriptions"
|
||||||
static let tags = "tags"
|
static let tags = "tags"
|
||||||
static let taggings = "taggings"
|
static let taggings = "taggings"
|
||||||
static let icons = "icons"
|
|
||||||
static let unreadEntries = "unreadEntries"
|
static let unreadEntries = "unreadEntries"
|
||||||
static let starredEntries = "starredEntries"
|
static let starredEntries = "starredEntries"
|
||||||
}
|
}
|
||||||
@ -149,9 +148,11 @@ final class FeedbinAPICaller: NSObject {
|
|||||||
|
|
||||||
func retrieveSubscriptions(completion: @escaping (Result<[FeedbinSubscription]?, Error>) -> Void) {
|
func retrieveSubscriptions(completion: @escaping (Result<[FeedbinSubscription]?, Error>) -> Void) {
|
||||||
|
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("subscriptions.json")
|
var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("subscriptions.json"), resolvingAgainstBaseURL: false)!
|
||||||
|
callComponents.queryItems = [URLQueryItem(name: "mode", value: "extended")]
|
||||||
|
|
||||||
let conditionalGet = accountMetadata?.conditionalGetInfo[ConditionalGetKeys.subscriptions]
|
let conditionalGet = accountMetadata?.conditionalGetInfo[ConditionalGetKeys.subscriptions]
|
||||||
let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet)
|
let request = URLRequest(url: callComponents.url!, credentials: credentials, conditionalGet: conditionalGet)
|
||||||
|
|
||||||
transport.send(request: request, resultType: [FeedbinSubscription].self) { result in
|
transport.send(request: request, resultType: [FeedbinSubscription].self) { result in
|
||||||
|
|
||||||
@ -169,8 +170,10 @@ final class FeedbinAPICaller: NSObject {
|
|||||||
|
|
||||||
func createSubscription(url: String, completion: @escaping (Result<CreateSubscriptionResult, Error>) -> Void) {
|
func createSubscription(url: String, completion: @escaping (Result<CreateSubscriptionResult, Error>) -> Void) {
|
||||||
|
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("subscriptions.json")
|
var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("subscriptions.json"), resolvingAgainstBaseURL: false)!
|
||||||
var request = URLRequest(url: callURL, credentials: credentials)
|
callComponents.queryItems = [URLQueryItem(name: "mode", value: "extended")]
|
||||||
|
|
||||||
|
var request = URLRequest(url: callComponents.url!, credentials: credentials)
|
||||||
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType)
|
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType)
|
||||||
|
|
||||||
let payload: Data
|
let payload: Data
|
||||||
@ -313,26 +316,6 @@ final class FeedbinAPICaller: NSObject {
|
|||||||
transport.send(request: request, method: HTTPMethod.delete, completion: completion)
|
transport.send(request: request, method: HTTPMethod.delete, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveIcons(completion: @escaping (Result<[FeedbinIcon]?, Error>) -> Void) {
|
|
||||||
|
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("icons.json")
|
|
||||||
let conditionalGet = accountMetadata?.conditionalGetInfo[ConditionalGetKeys.icons]
|
|
||||||
let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet)
|
|
||||||
|
|
||||||
transport.send(request: request, resultType: [FeedbinIcon].self) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success(let (response, icons)):
|
|
||||||
self.storeConditionalGet(key: ConditionalGetKeys.icons, headers: response.allHeaderFields)
|
|
||||||
completion(.success(icons))
|
|
||||||
case .failure(let error):
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func retrieveEntries(articleIDs: [String], completion: @escaping (Result<([FeedbinEntry]?), Error>) -> Void) {
|
func retrieveEntries(articleIDs: [String], completion: @escaping (Result<([FeedbinEntry]?), Error>) -> Void) {
|
||||||
|
|
||||||
guard !articleIDs.isEmpty else {
|
guard !articleIDs.isEmpty else {
|
||||||
|
@ -80,7 +80,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
retrieveCredentialsIfNecessary(account)
|
retrieveCredentialsIfNecessary(account)
|
||||||
|
|
||||||
refreshProgress.addToNumberOfTasksAndRemaining(6)
|
refreshProgress.addToNumberOfTasksAndRemaining(5)
|
||||||
|
|
||||||
refreshAccount(account) { result in
|
refreshAccount(account) { result in
|
||||||
switch result {
|
switch result {
|
||||||
@ -627,26 +627,14 @@ private extension FeedbinAccountDelegate {
|
|||||||
switch result {
|
switch result {
|
||||||
case .success(let taggings):
|
case .success(let taggings):
|
||||||
|
|
||||||
self.refreshProgress.completeTask()
|
BatchUpdate.shared.perform {
|
||||||
self.caller.retrieveIcons { result in
|
self.syncFolders(account, tags)
|
||||||
switch result {
|
self.syncFeeds(account, subscriptions)
|
||||||
case .success(let icons):
|
self.syncFeedFolderRelationship(account, taggings)
|
||||||
|
|
||||||
BatchUpdate.shared.perform {
|
|
||||||
self.syncFolders(account, tags)
|
|
||||||
self.syncFeeds(account, subscriptions)
|
|
||||||
self.syncFeedFolderRelationship(account, taggings)
|
|
||||||
self.syncFavicons(account, icons)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.refreshProgress.completeTask()
|
|
||||||
completion(.success(()))
|
|
||||||
|
|
||||||
case .failure(let error):
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.refreshProgress.completeTask()
|
||||||
|
completion(.success(()))
|
||||||
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
completion(.failure(error))
|
completion(.failure(error))
|
||||||
@ -811,6 +799,8 @@ private extension FeedbinAccountDelegate {
|
|||||||
feed.editedName = nil
|
feed.editedName = nil
|
||||||
feed.homePageURL = subscription.homePageURL
|
feed.homePageURL = subscription.homePageURL
|
||||||
feed.subscriptionID = String(subscription.subscriptionID)
|
feed.subscriptionID = String(subscription.subscriptionID)
|
||||||
|
feed.faviconURL = subscription.jsonFeed?.favicon
|
||||||
|
feed.iconURL = subscription.jsonFeed?.icon
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
subscriptionsToAdd.insert(subscription)
|
subscriptionsToAdd.insert(subscription)
|
||||||
@ -894,25 +884,6 @@ private extension FeedbinAccountDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncFavicons(_ account: Account, _ icons: [FeedbinIcon]?) {
|
|
||||||
|
|
||||||
guard let icons = icons else { return }
|
|
||||||
|
|
||||||
os_log(.debug, log: log, "Syncing favicons with %ld icons.", icons.count)
|
|
||||||
|
|
||||||
let iconDict = Dictionary(uniqueKeysWithValues: icons.map { ($0.host, $0.url) } )
|
|
||||||
|
|
||||||
for feed in account.flattenedFeeds() {
|
|
||||||
for (key, value) in iconDict {
|
|
||||||
if feed.homePageURL?.contains(key) ?? false {
|
|
||||||
feed.faviconURL = value
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func sendArticleStatuses(_ statuses: [SyncStatus],
|
func sendArticleStatuses(_ statuses: [SyncStatus],
|
||||||
apiCall: ([Int], @escaping (Result<Void, Error>) -> Void) -> Void,
|
apiCall: ([Int], @escaping (Result<Void, Error>) -> Void) -> Void,
|
||||||
completion: @escaping ((Result<Void, Error>) -> Void)) {
|
completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||||
@ -1008,11 +979,12 @@ private extension FeedbinAccountDelegate {
|
|||||||
|
|
||||||
func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||||
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
||||||
let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL)
|
let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL)
|
||||||
feed.subscriptionID = String(sub.subscriptionID)
|
feed.subscriptionID = String(sub.subscriptionID)
|
||||||
|
feed.iconURL = sub.jsonFeed?.icon
|
||||||
|
feed.faviconURL = sub.jsonFeed?.favicon
|
||||||
|
|
||||||
account.addFeed(feed, to: container) { result in
|
account.addFeed(feed, to: container) { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// FeedbinIcon.swift
|
|
||||||
// Account
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 5/6/19.
|
|
||||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct FeedbinIcon: Codable {
|
|
||||||
|
|
||||||
let host: String
|
|
||||||
let url: String
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case host
|
|
||||||
case url
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -17,6 +17,7 @@ struct FeedbinSubscription: Hashable, Codable {
|
|||||||
let name: String?
|
let name: String?
|
||||||
let url: String
|
let url: String
|
||||||
let homePageURL: String?
|
let homePageURL: String?
|
||||||
|
let jsonFeed: FeedbinSubscriptionJSONFeed?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case subscriptionID = "id"
|
case subscriptionID = "id"
|
||||||
@ -24,11 +25,26 @@ struct FeedbinSubscription: Hashable, Codable {
|
|||||||
case name = "title"
|
case name = "title"
|
||||||
case url = "feed_url"
|
case url = "feed_url"
|
||||||
case homePageURL = "site_url"
|
case homePageURL = "site_url"
|
||||||
|
case jsonFeed = "json_feed"
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(subscriptionID)
|
hasher.combine(subscriptionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func == (lhs: FeedbinSubscription, rhs: FeedbinSubscription) -> Bool {
|
||||||
|
return lhs.subscriptionID == rhs.subscriptionID
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FeedbinSubscriptionJSONFeed: Codable {
|
||||||
|
let favicon: String?
|
||||||
|
let icon: String?
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case favicon = "favicon"
|
||||||
|
case icon = "icon"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FeedbinCreateSubscription: Codable {
|
struct FeedbinCreateSubscription: Codable {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user