2017-05-27 19:43:27 +02:00
|
|
|
//
|
|
|
|
// ArticleUtilities.swift
|
2018-08-29 07:18:24 +02:00
|
|
|
// NetNewsWire
|
2017-05-27 19:43:27 +02:00
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 7/25/15.
|
|
|
|
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
2019-08-24 21:57:51 +02:00
|
|
|
import RSCore
|
2018-07-24 03:29:08 +02:00
|
|
|
import Articles
|
2017-09-17 21:34:10 +02:00
|
|
|
import Account
|
2017-05-27 19:43:27 +02:00
|
|
|
|
|
|
|
// These handle multiple accounts.
|
|
|
|
|
2017-10-29 19:14:10 +01:00
|
|
|
@discardableResult
|
|
|
|
func markArticles(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
2017-05-27 19:43:27 +02:00
|
|
|
|
2017-09-17 21:54:08 +02:00
|
|
|
let d: [String: Set<Article>] = accountAndArticlesDictionary(articles)
|
2017-10-29 19:14:10 +01:00
|
|
|
var updatedArticles = Set<Article>()
|
|
|
|
|
2017-10-09 06:06:25 +02:00
|
|
|
for (accountID, accountArticles) in d {
|
2017-05-27 19:43:27 +02:00
|
|
|
|
2017-10-09 06:06:25 +02:00
|
|
|
guard let account = AccountManager.shared.existingAccount(with: accountID) else {
|
2017-10-29 19:14:10 +01:00
|
|
|
continue
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
2017-10-29 19:14:10 +01:00
|
|
|
|
|
|
|
if let accountUpdatedArticles = account.markArticles(accountArticles, statusKey: statusKey, flag: flag) {
|
|
|
|
updatedArticles.formUnion(accountUpdatedArticles)
|
|
|
|
}
|
|
|
|
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
2017-10-29 19:14:10 +01:00
|
|
|
|
|
|
|
return updatedArticles
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
|
|
|
|
2017-09-17 21:54:08 +02:00
|
|
|
private func accountAndArticlesDictionary(_ articles: Set<Article>) -> [String: Set<Article>] {
|
2017-05-27 19:43:27 +02:00
|
|
|
|
2017-10-09 06:06:25 +02:00
|
|
|
let d = Dictionary(grouping: articles, by: { $0.accountID })
|
|
|
|
return d.mapValues{ Set($0) }
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
|
|
|
|
2017-09-17 21:54:08 +02:00
|
|
|
extension Article {
|
2017-05-27 19:43:27 +02:00
|
|
|
|
2017-09-18 02:03:58 +02:00
|
|
|
var feed: Feed? {
|
2019-09-09 06:44:05 +02:00
|
|
|
return account?.existingFeed(withFeedID: feedID)
|
2017-09-18 02:03:58 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 01:30:45 +02:00
|
|
|
var preferredLink: String? {
|
2019-09-08 03:27:48 +02:00
|
|
|
if let url = url, !url.isEmpty {
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
if let externalURL = externalURL, !externalURL.isEmpty {
|
|
|
|
return externalURL
|
|
|
|
}
|
|
|
|
return nil
|
2017-09-18 01:30:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var body: String? {
|
2018-02-14 22:14:25 +01:00
|
|
|
return contentHTML ?? contentText ?? summary
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
2017-09-18 02:03:58 +02:00
|
|
|
|
|
|
|
var logicalDatePublished: Date {
|
2018-02-14 22:14:25 +01:00
|
|
|
return datePublished ?? dateModified ?? status.dateArrived
|
2017-09-18 02:03:58 +02:00
|
|
|
}
|
2019-08-24 21:57:51 +02:00
|
|
|
|
2019-11-06 01:05:57 +01:00
|
|
|
func iconImage() -> IconImage? {
|
2019-11-07 21:29:16 +01:00
|
|
|
if let authors = authors, authors.count == 1, let author = authors.first {
|
|
|
|
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
|
|
|
return image
|
2019-08-24 21:57:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-07 21:29:16 +01:00
|
|
|
if let authors = feed?.authors, authors.count == 1, let author = authors.first {
|
|
|
|
if let image = appDelegate.authorAvatarDownloader.image(for: author) {
|
|
|
|
return image
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-24 21:57:51 +02:00
|
|
|
guard let feed = feed else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
let feedIconImage = appDelegate.feedIconDownloader.icon(for: feed)
|
|
|
|
if feedIconImage != nil {
|
|
|
|
return feedIconImage
|
|
|
|
}
|
|
|
|
|
2019-11-06 01:05:57 +01:00
|
|
|
if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: feed) {
|
2019-08-24 21:57:51 +02:00
|
|
|
return faviconImage
|
|
|
|
}
|
|
|
|
|
|
|
|
return FaviconGenerator.favicon(feed)
|
|
|
|
}
|
2017-05-27 19:43:27 +02:00
|
|
|
}
|
2019-09-08 23:48:50 +02:00
|
|
|
|
2019-11-14 22:06:32 +01:00
|
|
|
// MARK: Path
|
2019-10-03 16:53:21 +02:00
|
|
|
|
2019-11-14 22:06:32 +01:00
|
|
|
struct ArticlePathKey {
|
|
|
|
static let accountID = "accountID"
|
|
|
|
static let accountName = "accountName"
|
|
|
|
static let feedID = "feedID"
|
|
|
|
static let articleID = "articleID"
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Article {
|
2019-10-03 16:53:21 +02:00
|
|
|
|
2019-11-14 22:06:32 +01:00
|
|
|
public var pathUserInfo: [AnyHashable : Any] {
|
2019-10-03 16:53:21 +02:00
|
|
|
return [
|
2019-11-14 22:06:32 +01:00
|
|
|
ArticlePathKey.accountID: accountID,
|
|
|
|
ArticlePathKey.accountName: account?.nameForDisplay ?? "",
|
|
|
|
ArticlePathKey.feedID: feedID,
|
|
|
|
ArticlePathKey.articleID: articleID
|
2019-10-03 16:53:21 +02:00
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-09-08 23:48:50 +02:00
|
|
|
// MARK: SortableArticle
|
|
|
|
|
|
|
|
extension Article: SortableArticle {
|
|
|
|
|
|
|
|
var sortableName: String {
|
|
|
|
return feed?.name ?? ""
|
|
|
|
}
|
|
|
|
|
|
|
|
var sortableDate: Date {
|
|
|
|
return logicalDatePublished
|
|
|
|
}
|
|
|
|
|
2019-09-13 14:43:28 +02:00
|
|
|
var sortableArticleID: String {
|
2019-09-08 23:48:50 +02:00
|
|
|
return articleID
|
|
|
|
}
|
|
|
|
|
2019-09-13 14:43:28 +02:00
|
|
|
var sortableFeedID: String {
|
|
|
|
return feedID
|
|
|
|
}
|
|
|
|
|
2019-09-08 23:48:50 +02:00
|
|
|
}
|