mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Rename WebFeed type to just Feed.
This commit is contained in:
@@ -55,7 +55,7 @@ public enum FetchType {
|
||||
case unread(_: Int? = nil)
|
||||
case today(_: Int? = nil)
|
||||
case folder(Folder, Bool)
|
||||
case webFeed(WebFeed)
|
||||
case webFeed(Feed)
|
||||
case articleIDs(Set<String>)
|
||||
case search(String)
|
||||
case searchWithArticleIDs(String, Set<String>)
|
||||
@@ -139,7 +139,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
}
|
||||
|
||||
public var topLevelFeeds = Set<WebFeed>()
|
||||
public var topLevelFeeds = Set<Feed>()
|
||||
public var folders: Set<Folder>? = Set<Folder>()
|
||||
|
||||
public var externalID: String? {
|
||||
@@ -159,15 +159,15 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
|
||||
private var feedDictionariesNeedUpdate = true
|
||||
private var _idToFeedDictionary = [String: WebFeed]()
|
||||
var idToFeedDictionary: [String: WebFeed] {
|
||||
private var _idToFeedDictionary = [String: Feed]()
|
||||
var idToFeedDictionary: [String: Feed] {
|
||||
if feedDictionariesNeedUpdate {
|
||||
rebuildFeedDictionaries()
|
||||
}
|
||||
return _idToFeedDictionary
|
||||
}
|
||||
private var _externalIDToFeedDictionary = [String: WebFeed]()
|
||||
var externalIDToFeedDictionary: [String: WebFeed] {
|
||||
private var _externalIDToFeedDictionary = [String: Feed]()
|
||||
var externalIDToFeedDictionary: [String: Feed] {
|
||||
if feedDictionariesNeedUpdate {
|
||||
rebuildFeedDictionaries()
|
||||
}
|
||||
@@ -210,7 +210,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
|
||||
private var unreadCounts = [String: Int]() // [feedID: Int]
|
||||
|
||||
private var _flattenedFeeds = Set<WebFeed>()
|
||||
private var _flattenedFeeds = Set<Feed>()
|
||||
private var flattenedFeedsNeedUpdate = true
|
||||
|
||||
private lazy var opmlFile = OPMLFile(filename: (dataFolder as NSString).appendingPathComponent("Subscriptions.opml"), account: self)
|
||||
@@ -331,7 +331,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
self.metadata.performedApril2020RetentionPolicyChange = true
|
||||
}
|
||||
|
||||
self.database.cleanupDatabaseAtStartup(subscribedToFeedIDs: self.flattenedFeeds().webFeedIDs())
|
||||
self.database.cleanupDatabaseAtStartup(subscribedToFeedIDs: self.flattenedFeeds().feedIDs())
|
||||
self.fetchAllUnreadCounts()
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return existingFolder(withExternalID: externalID)
|
||||
}
|
||||
|
||||
func existingContainers(withFeed feed: WebFeed) -> [Container] {
|
||||
func existingContainers(withFeed feed: Feed) -> [Container] {
|
||||
var containers = [Container]()
|
||||
if topLevelFeeds.contains(feed) {
|
||||
containers.append(self)
|
||||
@@ -575,10 +575,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return folders?.first(where: { $0.externalID == externalID })
|
||||
}
|
||||
|
||||
func newFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> WebFeed {
|
||||
func newFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> Feed {
|
||||
let feedURL = opmlFeedSpecifier.feedURL
|
||||
let metadata = feedMetadata(feedURL: feedURL, feedID: feedURL)
|
||||
let feed = WebFeed(account: self, url: opmlFeedSpecifier.feedURL, metadata: metadata)
|
||||
let feed = Feed(account: self, url: opmlFeedSpecifier.feedURL, metadata: metadata)
|
||||
if let feedTitle = opmlFeedSpecifier.title {
|
||||
if feed.name == nil {
|
||||
feed.name = feedTitle
|
||||
@@ -587,35 +587,35 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return feed
|
||||
}
|
||||
|
||||
public func addFeed(_ feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func addFeed(_ feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.addFeed(for: self, with: feed, to: container, completion: completion)
|
||||
}
|
||||
|
||||
public func createFeed(url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
public func createFeed(url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
delegate.createFeed(for: self, url: url, name: name, container: container, validateFeed: validateFeed, completion: completion)
|
||||
}
|
||||
|
||||
func createFeed(with name: String?, url: String, feedID: String, homePageURL: String?) -> WebFeed {
|
||||
func createFeed(with name: String?, url: String, feedID: String, homePageURL: String?) -> Feed {
|
||||
let metadata = feedMetadata(feedURL: url, feedID: feedID)
|
||||
let feed = WebFeed(account: self, url: url, metadata: metadata)
|
||||
let feed = Feed(account: self, url: url, metadata: metadata)
|
||||
feed.name = name
|
||||
feed.homePageURL = homePageURL
|
||||
return feed
|
||||
}
|
||||
|
||||
public func removeFeed(_ feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func removeFeed(_ feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.removeFeed(for: self, with: feed, from: container, completion: completion)
|
||||
}
|
||||
|
||||
public func moveFeed(_ feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func moveFeed(_ feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.moveFeed(for: self, with: feed, from: from, to: to, completion: completion)
|
||||
}
|
||||
|
||||
public func renameFeed(_ feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func renameFeed(_ feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.renameFeed(for: self, with: feed, to: name, completion: completion)
|
||||
}
|
||||
|
||||
public func restoreFeed(_ feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func restoreFeed(_ feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.restoreFeed(for: self, feed: feed, container: container, completion: completion)
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
delegate.markArticles(for: self, articles: articles, statusKey: statusKey, flag: flag, completion: completion)
|
||||
}
|
||||
|
||||
func clearFeedMetadata(_ feed: WebFeed) {
|
||||
func clearFeedMetadata(_ feed: Feed) {
|
||||
feedMetadata[feed.url] = nil
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
structureDidChange()
|
||||
}
|
||||
|
||||
public func updateUnreadCounts(for feeds: Set<WebFeed>, completion: VoidCompletionBlock? = nil) {
|
||||
public func updateUnreadCounts(for feeds: Set<Feed>, completion: VoidCompletionBlock? = nil) {
|
||||
fetchUnreadCounts(for: feeds, completion: completion)
|
||||
}
|
||||
|
||||
@@ -661,8 +661,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return try fetchUnreadArticlesBetween(forContainer: folder, limit: limit, before: before, after: after)
|
||||
}
|
||||
|
||||
public func fetchUnreadArticlesBetween(feeds: Set<WebFeed>, limit: Int?, before: Date?, after: Date?) throws -> Set<Article> {
|
||||
let articles = try database.fetchUnreadArticlesBetween(feeds.webFeedIDs(), limit, before, after)
|
||||
public func fetchUnreadArticlesBetween(feeds: Set<Feed>, limit: Int?, before: Date?, after: Date?) throws -> Set<Article> {
|
||||
let articles = try database.fetchUnreadArticlesBetween(feeds.feedIDs(), limit, before, after)
|
||||
return articles
|
||||
}
|
||||
|
||||
@@ -721,15 +721,15 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
|
||||
public func fetchUnreadCountForToday(_ completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
database.fetchUnreadCountForToday(for: flattenedFeeds().webFeedIDs(), completion: completion)
|
||||
database.fetchUnreadCountForToday(for: flattenedFeeds().feedIDs(), completion: completion)
|
||||
}
|
||||
|
||||
public func fetchUnreadCountForStarredArticles(_ completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
database.fetchStarredAndUnreadCount(for: flattenedFeeds().webFeedIDs(), completion: completion)
|
||||
database.fetchStarredAndUnreadCount(for: flattenedFeeds().feedIDs(), completion: completion)
|
||||
}
|
||||
|
||||
public func fetchCountForStarredArticles() throws -> Int {
|
||||
return try database.fetchStarredArticlesCount(flattenedFeeds().webFeedIDs())
|
||||
return try database.fetchStarredArticlesCount(flattenedFeeds().feedIDs())
|
||||
}
|
||||
|
||||
public func fetchUnreadArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) {
|
||||
@@ -745,12 +745,12 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
database.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate(completion)
|
||||
}
|
||||
|
||||
public func unreadCount(for feed: WebFeed) -> Int {
|
||||
return unreadCounts[feed.webFeedID] ?? 0
|
||||
public func unreadCount(for feed: Feed) -> Int {
|
||||
return unreadCounts[feed.feedID] ?? 0
|
||||
}
|
||||
|
||||
public func setUnreadCount(_ unreadCount: Int, for webFeed: WebFeed) {
|
||||
unreadCounts[webFeed.webFeedID] = unreadCount
|
||||
public func setUnreadCount(_ unreadCount: Int, for webFeed: Feed) {
|
||||
unreadCounts[webFeed.feedID] = unreadCount
|
||||
}
|
||||
|
||||
public func structureDidChange() {
|
||||
@@ -761,7 +761,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
feedDictionariesNeedUpdate = true
|
||||
}
|
||||
|
||||
func update(_ feed: WebFeed, with parsedFeed: ParsedFeed, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||
func update(_ feed: Feed, with parsedFeed: ParsedFeed, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||
// Used only by an On My Mac or iCloud account.
|
||||
precondition(Thread.isMainThread)
|
||||
precondition(type == .onMyMac || type == .cloudKit)
|
||||
@@ -773,7 +773,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return
|
||||
}
|
||||
|
||||
update(feed.webFeedID, with: parsedItems, completion: completion)
|
||||
update(feed.feedID, with: parsedItems, completion: completion)
|
||||
}
|
||||
|
||||
func update(_ feedID: String, with parsedItems: Set<ParsedItem>, deleteOlder: Bool = true, completion: @escaping UpdateArticlesCompletionBlock) {
|
||||
@@ -907,7 +907,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
|
||||
// MARK: - Container
|
||||
|
||||
public func flattenedFeeds() -> Set<WebFeed> {
|
||||
public func flattenedFeeds() -> Set<Feed> {
|
||||
assert(Thread.isMainThread)
|
||||
if flattenedFeedsNeedUpdate {
|
||||
updateFlattenedFeeds()
|
||||
@@ -915,13 +915,13 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return _flattenedFeeds
|
||||
}
|
||||
|
||||
public func removeFeed(_ feed: WebFeed) {
|
||||
public func removeFeed(_ feed: Feed) {
|
||||
topLevelFeeds.remove(feed)
|
||||
structureDidChange()
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
public func removeFeeds(_ feeds: Set<WebFeed>) {
|
||||
public func removeFeeds(_ feeds: Set<Feed>) {
|
||||
guard !feeds.isEmpty else {
|
||||
return
|
||||
}
|
||||
@@ -930,13 +930,13 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
public func addFeed(_ feed: WebFeed) {
|
||||
public func addFeed(_ feed: Feed) {
|
||||
topLevelFeeds.insert(feed)
|
||||
structureDidChange()
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
func addFeedIfNotInAnyFolder(_ feed: WebFeed) {
|
||||
func addFeedIfNotInAnyFolder(_ feed: Feed) {
|
||||
if !flattenedFeeds().contains(feed) {
|
||||
addFeed(feed)
|
||||
}
|
||||
@@ -978,7 +978,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
|
||||
@objc func unreadCountDidChange(_ note: Notification) {
|
||||
if let feed = note.object as? WebFeed, feed.account === self {
|
||||
if let feed = note.object as? Feed, feed.account === self {
|
||||
updateUnreadCount()
|
||||
}
|
||||
}
|
||||
@@ -1047,11 +1047,11 @@ extension Account: FeedMetadataDelegate {
|
||||
private extension Account {
|
||||
|
||||
func fetchStarredArticles(limit: Int?) throws -> Set<Article> {
|
||||
return try database.fetchStarredArticles(flattenedFeeds().webFeedIDs(), limit)
|
||||
return try database.fetchStarredArticles(flattenedFeeds().feedIDs(), limit)
|
||||
}
|
||||
|
||||
func fetchStarredArticlesAsync(limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
database.fetchedStarredArticlesAsync(flattenedFeeds().webFeedIDs(), limit, completion)
|
||||
database.fetchedStarredArticlesAsync(flattenedFeeds().feedIDs(), limit, completion)
|
||||
}
|
||||
|
||||
func fetchUnreadArticles(limit: Int?) throws -> Set<Article> {
|
||||
@@ -1063,11 +1063,11 @@ private extension Account {
|
||||
}
|
||||
|
||||
func fetchTodayArticles(limit: Int?) throws -> Set<Article> {
|
||||
return try database.fetchTodayArticles(flattenedFeeds().webFeedIDs(), limit)
|
||||
return try database.fetchTodayArticles(flattenedFeeds().feedIDs(), limit)
|
||||
}
|
||||
|
||||
func fetchTodayArticlesAsync(limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
database.fetchTodayArticlesAsync(flattenedFeeds().webFeedIDs(), limit, completion)
|
||||
database.fetchTodayArticlesAsync(flattenedFeeds().feedIDs(), limit, completion)
|
||||
}
|
||||
|
||||
func fetchArticles(folder: Folder) throws -> Set<Article> {
|
||||
@@ -1086,14 +1086,14 @@ private extension Account {
|
||||
fetchUnreadArticlesAsync(forContainer: folder, limit: nil, completion)
|
||||
}
|
||||
|
||||
func fetchArticles(feed: WebFeed) throws -> Set<Article> {
|
||||
let articles = try database.fetchArticles(feed.webFeedID)
|
||||
func fetchArticles(feed: Feed) throws -> Set<Article> {
|
||||
let articles = try database.fetchArticles(feed.feedID)
|
||||
validateUnreadCount(feed, articles)
|
||||
return articles
|
||||
}
|
||||
|
||||
func fetchArticlesAsync(feed: WebFeed, _ completion: @escaping ArticleSetResultBlock) {
|
||||
database.fetchArticlesAsync(feed.webFeedID) { [weak self] articleSetResult in
|
||||
func fetchArticlesAsync(feed: Feed, _ completion: @escaping ArticleSetResultBlock) {
|
||||
database.fetchArticlesAsync(feed.feedID) { [weak self] articleSetResult in
|
||||
switch articleSetResult {
|
||||
case .success(let articles):
|
||||
self?.validateUnreadCount(feed, articles)
|
||||
@@ -1105,7 +1105,7 @@ private extension Account {
|
||||
}
|
||||
|
||||
func fetchArticlesMatching(_ searchString: String) throws -> Set<Article> {
|
||||
return try database.fetchArticlesMatching(searchString, flattenedFeeds().webFeedIDs())
|
||||
return try database.fetchArticlesMatching(searchString, flattenedFeeds().feedIDs())
|
||||
}
|
||||
|
||||
func fetchArticlesMatchingWithArticleIDs(_ searchString: String, _ articleIDs: Set<String>) throws -> Set<Article> {
|
||||
@@ -1113,7 +1113,7 @@ private extension Account {
|
||||
}
|
||||
|
||||
func fetchArticlesMatchingAsync(_ searchString: String, _ completion: @escaping ArticleSetResultBlock) {
|
||||
database.fetchArticlesMatchingAsync(searchString, flattenedFeeds().webFeedIDs(), completion)
|
||||
database.fetchArticlesMatchingAsync(searchString, flattenedFeeds().feedIDs(), completion)
|
||||
}
|
||||
|
||||
func fetchArticlesMatchingWithArticleIDsAsync(_ searchString: String, _ articleIDs: Set<String>, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@@ -1128,22 +1128,22 @@ private extension Account {
|
||||
return database.fetchArticlesAsync(articleIDs: articleIDs, completion)
|
||||
}
|
||||
|
||||
func fetchUnreadArticles(feed: WebFeed) throws -> Set<Article> {
|
||||
let articles = try database.fetchUnreadArticles(Set([feed.webFeedID]), nil)
|
||||
func fetchUnreadArticles(feed: Feed) throws -> Set<Article> {
|
||||
let articles = try database.fetchUnreadArticles(Set([feed.feedID]), nil)
|
||||
validateUnreadCount(feed, articles)
|
||||
return articles
|
||||
}
|
||||
|
||||
func fetchArticles(forContainer container: Container) throws -> Set<Article> {
|
||||
let feeds = container.flattenedFeeds()
|
||||
let articles = try database.fetchArticles(feeds.webFeedIDs())
|
||||
let articles = try database.fetchArticles(feeds.feedIDs())
|
||||
validateUnreadCountsAfterFetchingUnreadArticles(feeds, articles)
|
||||
return articles
|
||||
}
|
||||
|
||||
func fetchArticlesAsync(forContainer container: Container, _ completion: @escaping ArticleSetResultBlock) {
|
||||
let feeds = container.flattenedFeeds()
|
||||
database.fetchArticlesAsync(feeds.webFeedIDs()) { [weak self] (articleSetResult) in
|
||||
database.fetchArticlesAsync(feeds.feedIDs()) { [weak self] (articleSetResult) in
|
||||
switch articleSetResult {
|
||||
case .success(let articles):
|
||||
self?.validateUnreadCountsAfterFetchingUnreadArticles(feeds, articles)
|
||||
@@ -1156,7 +1156,7 @@ private extension Account {
|
||||
|
||||
func fetchUnreadArticles(forContainer container: Container, limit: Int?) throws -> Set<Article> {
|
||||
let feeds = container.flattenedFeeds()
|
||||
let articles = try database.fetchUnreadArticles(feeds.webFeedIDs(), limit)
|
||||
let articles = try database.fetchUnreadArticles(feeds.feedIDs(), limit)
|
||||
|
||||
// We don't validate limit queries because they, by definition, won't correctly match the
|
||||
// complete unread state for the given container.
|
||||
@@ -1169,13 +1169,13 @@ private extension Account {
|
||||
|
||||
func fetchUnreadArticlesBetween(forContainer container: Container, limit: Int?, before: Date?, after: Date?) throws -> Set<Article> {
|
||||
let feeds = container.flattenedFeeds()
|
||||
let articles = try database.fetchUnreadArticlesBetween(feeds.webFeedIDs(), limit, before, after)
|
||||
let articles = try database.fetchUnreadArticlesBetween(feeds.feedIDs(), limit, before, after)
|
||||
return articles
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesAsync(forContainer container: Container, limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
let feeds = container.flattenedFeeds()
|
||||
database.fetchUnreadArticlesAsync(feeds.webFeedIDs(), limit) { [weak self] (articleSetResult) in
|
||||
database.fetchUnreadArticlesAsync(feeds.feedIDs(), limit) { [weak self] (articleSetResult) in
|
||||
switch articleSetResult {
|
||||
case .success(let articles):
|
||||
|
||||
@@ -1192,7 +1192,7 @@ private extension Account {
|
||||
}
|
||||
}
|
||||
|
||||
func validateUnreadCountsAfterFetchingUnreadArticles(_ feeds: Set<WebFeed>, _ articles: Set<Article>) {
|
||||
func validateUnreadCountsAfterFetchingUnreadArticles(_ feeds: Set<Feed>, _ articles: Set<Article>) {
|
||||
// Validate unread counts. This was the site of a performance slowdown:
|
||||
// it was calling going through the entire list of articles once per feed:
|
||||
// feeds.forEach { validateUnreadCount($0, articles) }
|
||||
@@ -1203,12 +1203,12 @@ private extension Account {
|
||||
unreadCountStorage[article.feedID, default: 0] += 1
|
||||
}
|
||||
feeds.forEach { (feed) in
|
||||
let unreadCount = unreadCountStorage[feed.webFeedID, default: 0]
|
||||
let unreadCount = unreadCountStorage[feed.feedID, default: 0]
|
||||
feed.unreadCount = unreadCount
|
||||
}
|
||||
}
|
||||
|
||||
func validateUnreadCount(_ feed: WebFeed, _ articles: Set<Article>) {
|
||||
func validateUnreadCount(_ feed: Feed, _ articles: Set<Article>) {
|
||||
// articles must contain all the unread articles for the feed.
|
||||
// The unread number should match the feed’s unread count.
|
||||
|
||||
@@ -1239,7 +1239,7 @@ private extension Account {
|
||||
}
|
||||
|
||||
func updateFlattenedFeeds() {
|
||||
var feeds = Set<WebFeed>()
|
||||
var feeds = Set<Feed>()
|
||||
feeds.formUnion(topLevelFeeds)
|
||||
for folder in folders! {
|
||||
feeds.formUnion(folder.flattenedFeeds())
|
||||
@@ -1250,11 +1250,11 @@ private extension Account {
|
||||
}
|
||||
|
||||
func rebuildFeedDictionaries() {
|
||||
var idDictionary = [String: WebFeed]()
|
||||
var externalIDDictionary = [String: WebFeed]()
|
||||
var idDictionary = [String: Feed]()
|
||||
var externalIDDictionary = [String: Feed]()
|
||||
|
||||
flattenedFeeds().forEach { (feed) in
|
||||
idDictionary[feed.webFeedID] = feed
|
||||
idDictionary[feed.feedID] = feed
|
||||
if let externalID = feed.externalID {
|
||||
externalIDDictionary[externalID] = feed
|
||||
}
|
||||
@@ -1301,7 +1301,7 @@ private extension Account {
|
||||
/// Fetch unread counts for zero or more feeds.
|
||||
///
|
||||
/// Uses the most efficient method based on how many feeds were passed in.
|
||||
func fetchUnreadCounts(for feeds: Set<WebFeed>, completion: VoidCompletionBlock?) {
|
||||
func fetchUnreadCounts(for feeds: Set<Feed>, completion: VoidCompletionBlock?) {
|
||||
if feeds.isEmpty {
|
||||
completion?()
|
||||
return
|
||||
@@ -1317,8 +1317,8 @@ private extension Account {
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUnreadCount(_ feed: WebFeed, _ completion: VoidCompletionBlock?) {
|
||||
database.fetchUnreadCount(feed.webFeedID) { result in
|
||||
func fetchUnreadCount(_ feed: Feed, _ completion: VoidCompletionBlock?) {
|
||||
database.fetchUnreadCount(feed.feedID) { result in
|
||||
if let unreadCount = try? result.get() {
|
||||
feed.unreadCount = unreadCount
|
||||
}
|
||||
@@ -1326,8 +1326,8 @@ private extension Account {
|
||||
}
|
||||
}
|
||||
|
||||
func fetchUnreadCounts(_ feeds: Set<WebFeed>, _ completion: VoidCompletionBlock?) {
|
||||
let feedIDs = Set(feeds.map { $0.webFeedID })
|
||||
func fetchUnreadCounts(_ feeds: Set<Feed>, _ completion: VoidCompletionBlock?) {
|
||||
let feedIDs = Set(feeds.map { $0.feedID })
|
||||
database.fetchUnreadCounts(for: feedIDs) { result in
|
||||
if let unreadCountDictionary = try? result.get() {
|
||||
self.processUnreadCounts(unreadCountDictionary: unreadCountDictionary, feeds: feeds)
|
||||
@@ -1356,16 +1356,16 @@ private extension Account {
|
||||
}
|
||||
}
|
||||
|
||||
func processUnreadCounts(unreadCountDictionary: UnreadCountDictionary, feeds: Set<WebFeed>) {
|
||||
func processUnreadCounts(unreadCountDictionary: UnreadCountDictionary, feeds: Set<Feed>) {
|
||||
for feed in feeds {
|
||||
// When the unread count is zero, it won’t appear in unreadCountDictionary.
|
||||
let unreadCount = unreadCountDictionary[feed.webFeedID] ?? 0
|
||||
let unreadCount = unreadCountDictionary[feed.feedID] ?? 0
|
||||
feed.unreadCount = unreadCount
|
||||
}
|
||||
}
|
||||
|
||||
func sendNotificationAbout(_ articleChanges: ArticleChanges) {
|
||||
var feeds = Set<WebFeed>()
|
||||
var feeds = Set<Feed>()
|
||||
|
||||
if let newArticles = articleChanges.newArticles {
|
||||
feeds.formUnion(Set(newArticles.compactMap { $0.feed }))
|
||||
@@ -1408,11 +1408,11 @@ private extension Account {
|
||||
|
||||
extension Account {
|
||||
|
||||
public func existingFeed(withFeedID feedID: String) -> WebFeed? {
|
||||
public func existingFeed(withFeedID feedID: String) -> Feed? {
|
||||
return idToFeedDictionary[feedID]
|
||||
}
|
||||
|
||||
public func existingFeed(withExternalID externalID: String) -> WebFeed? {
|
||||
public func existingFeed(withExternalID externalID: String) -> Feed? {
|
||||
return externalIDToFeedDictionary[externalID]
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ protocol AccountDelegate {
|
||||
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void)
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func addFeed(for account: Account, with: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void)
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func addFeed(for account: Account, with: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func restoreFolder(for account: Account, folder: Folder, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
|
||||
@@ -369,7 +369,7 @@ public final class AccountManager: UnreadCountProvider {
|
||||
/// Return true if a feed is for reddit.com and the path doesn’t end with .rss.
|
||||
///
|
||||
/// More info: [Pathogen-David's Guide to RSS and Reddit!](https://www.reddit.com/r/pathogendavid/comments/tv8m9/pathogendavids_guide_to_rss_and_reddit/)
|
||||
private func feedRequiresRedditAPI(_ feed: WebFeed) -> Bool {
|
||||
private func feedRequiresRedditAPI(_ feed: Feed) -> Bool {
|
||||
if let components = URLComponents(string: feed.url), let host = components.host {
|
||||
return host.hasSuffix("reddit.com") && !components.path.hasSuffix(".rss")
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public protocol ArticleFetcher {
|
||||
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock)
|
||||
}
|
||||
|
||||
extension WebFeed: ArticleFetcher {
|
||||
extension Feed: ArticleFetcher {
|
||||
|
||||
public func fetchArticles() throws -> Set<Article> {
|
||||
return try account?.fetchArticles(.webFeed(self)) ?? Set<Article>()
|
||||
|
||||
@@ -172,7 +172,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url urlString: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(for account: Account, url urlString: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
guard let url = URL(string: urlString) else {
|
||||
completion(.failure(LocalAccountDelegateError.invalidParameter))
|
||||
return
|
||||
@@ -184,7 +184,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
createRSSFeed(for: account, url: url, editedName: editedName, container: container, validateFeed: validateFeed, completion: completion)
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
let editedName = name.isEmpty ? nil : name
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
accountZone.renameFeed(feed, editedName: editedName) { result in
|
||||
@@ -200,7 +200,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
removeFeedFromCloud(for: account, with: feed, from: container) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@@ -220,7 +220,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from fromContainer: Container, to toContainer: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from fromContainer: Container, to toContainer: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
accountZone.moveFeed(feed, from: fromContainer, to: toContainer) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
@@ -236,7 +236,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
accountZone.addFeed(feed, to: container) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
@@ -251,7 +251,7 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
createFeed(for: account, url: feed.url, name: feed.editedName, container: container, validateFeed: true) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@@ -565,7 +565,7 @@ private extension CloudKitAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func combinedRefresh(_ account: Account, _ webFeeds: Set<WebFeed>, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func combinedRefresh(_ account: Account, _ webFeeds: Set<Feed>, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
@@ -579,7 +579,7 @@ private extension CloudKitAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
func addDeadFeed() {
|
||||
let feed = account.createFeed(with: editedName, url: url.absoluteString, feedID: url.absoluteString, homePageURL: nil)
|
||||
@@ -686,7 +686,7 @@ private extension CloudKitAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func sendNewArticlesToTheCloud(_ account: Account, _ feed: WebFeed) {
|
||||
func sendNewArticlesToTheCloud(_ account: Account, _ feed: Feed) {
|
||||
account.fetchArticlesAsync(.webFeed(feed)) { result in
|
||||
switch result {
|
||||
case .success(let articles):
|
||||
@@ -774,7 +774,7 @@ private extension CloudKitAccountDelegate {
|
||||
}
|
||||
|
||||
|
||||
func removeFeedFromCloud(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeedFromCloud(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(2)
|
||||
accountZone.removeFeed(feed, from: container) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
@@ -801,7 +801,7 @@ private extension CloudKitAccountDelegate {
|
||||
|
||||
extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
|
||||
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed) {
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed) {
|
||||
refreshProgress.completeTask()
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
}
|
||||
|
||||
/// Rename the given web feed
|
||||
func renameFeed(_ webFeed: WebFeed, editedName: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(_ webFeed: Feed, editedName: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let externalID = webFeed.externalID else {
|
||||
completion(.failure(CloudKitZoneError.corruptAccount))
|
||||
return
|
||||
@@ -138,7 +138,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
}
|
||||
|
||||
/// Removes a web feed from a container and optionally deletes it, calling the completion with true if deleted
|
||||
func removeFeed(_ webFeed: WebFeed, from: Container, completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
func removeFeed(_ webFeed: Feed, from: Container, completion: @escaping (Result<Bool, Error>) -> Void) {
|
||||
guard let fromContainerExternalID = from.externalID else {
|
||||
completion(.failure(CloudKitZoneError.corruptAccount))
|
||||
return
|
||||
@@ -187,7 +187,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(_ webFeed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(_ webFeed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let fromContainerExternalID = from.externalID, let toContainerExternalID = to.externalID else {
|
||||
completion(.failure(CloudKitZoneError.corruptAccount))
|
||||
return
|
||||
@@ -209,7 +209,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(_ webFeed: WebFeed, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(_ webFeed: Feed, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let toContainerExternalID = to.externalID else {
|
||||
completion(.failure(CloudKitZoneError.corruptAccount))
|
||||
return
|
||||
|
||||
@@ -17,7 +17,7 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
|
||||
|
||||
private typealias UnclaimedWebFeed = (url: URL, name: String?, editedName: String?, homePageURL: String?, webFeedExternalID: String)
|
||||
private var newUnclaimedWebFeeds = [String: [UnclaimedWebFeed]]()
|
||||
private var existingUnclaimedWebFeeds = [String: [WebFeed]]()
|
||||
private var existingUnclaimedWebFeeds = [String: [Feed]]()
|
||||
|
||||
private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit")
|
||||
|
||||
@@ -140,7 +140,7 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
|
||||
|
||||
private extension CloudKitAcountZoneDelegate {
|
||||
|
||||
func updateWebFeed(_ webFeed: WebFeed, name: String?, editedName: String?, homePageURL: String?, containerExternalIDs: [String]) {
|
||||
func updateWebFeed(_ webFeed: Feed, name: String?, editedName: String?, homePageURL: String?, containerExternalIDs: [String]) {
|
||||
guard let account = account else { return }
|
||||
|
||||
webFeed.name = name
|
||||
@@ -192,12 +192,12 @@ private extension CloudKitAcountZoneDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func addExistingUnclaimedWebFeed(_ webFeed: WebFeed, containerExternalID: String) {
|
||||
func addExistingUnclaimedWebFeed(_ webFeed: Feed, containerExternalID: String) {
|
||||
if var unclaimedWebFeeds = self.existingUnclaimedWebFeeds[containerExternalID] {
|
||||
unclaimedWebFeeds.append(webFeed)
|
||||
self.existingUnclaimedWebFeeds[containerExternalID] = unclaimedWebFeeds
|
||||
} else {
|
||||
var unclaimedWebFeeds = [WebFeed]()
|
||||
var unclaimedWebFeeds = [Feed]()
|
||||
unclaimedWebFeeds.append(webFeed)
|
||||
self.existingUnclaimedWebFeeds[containerExternalID] = unclaimedWebFeeds
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ extension Notification.Name {
|
||||
public protocol Container: AnyObject, ContainerIdentifiable {
|
||||
|
||||
var account: Account? { get }
|
||||
var topLevelFeeds: Set<WebFeed> { get set }
|
||||
var topLevelFeeds: Set<Feed> { get set }
|
||||
var folders: Set<Folder>? { get set }
|
||||
var externalID: String? { get set }
|
||||
|
||||
@@ -29,17 +29,17 @@ public protocol Container: AnyObject, ContainerIdentifiable {
|
||||
func hasChildFolder(with: String) -> Bool
|
||||
func childFolder(with: String) -> Folder?
|
||||
|
||||
func removeFeed(_ webFeed: WebFeed)
|
||||
func addFeed(_ webFeed: WebFeed)
|
||||
func removeFeed(_ feed: Feed)
|
||||
func addFeed(_ feed: Feed)
|
||||
|
||||
//Recursive — checks subfolders
|
||||
func flattenedFeeds() -> Set<WebFeed>
|
||||
func has(_ webFeed: WebFeed) -> Bool
|
||||
func flattenedFeeds() -> Set<Feed>
|
||||
func has(_ feed: Feed) -> Bool
|
||||
func hasFeed(with feedID: String) -> Bool
|
||||
func hasFeed(withURL url: String) -> Bool
|
||||
func existingFeed(withFeedID: String) -> WebFeed?
|
||||
func existingFeed(withURL url: String) -> WebFeed?
|
||||
func existingFeed(withExternalID externalID: String) -> WebFeed?
|
||||
func existingFeed(withFeedID: String) -> Feed?
|
||||
func existingFeed(withURL url: String) -> Feed?
|
||||
func existingFeed(withExternalID externalID: String) -> Feed?
|
||||
func existingFolder(with name: String) -> Folder?
|
||||
func existingFolder(withID: Int) -> Folder?
|
||||
|
||||
@@ -69,7 +69,7 @@ public extension Container {
|
||||
}
|
||||
|
||||
func objectIsChild(_ object: AnyObject) -> Bool {
|
||||
if let feed = object as? WebFeed {
|
||||
if let feed = object as? Feed {
|
||||
return topLevelFeeds.contains(feed)
|
||||
}
|
||||
if let folder = object as? Folder {
|
||||
@@ -78,8 +78,8 @@ public extension Container {
|
||||
return false
|
||||
}
|
||||
|
||||
func flattenedFeeds() -> Set<WebFeed> {
|
||||
var feeds = Set<WebFeed>()
|
||||
func flattenedFeeds() -> Set<Feed> {
|
||||
var feeds = Set<Feed>()
|
||||
feeds.formUnion(topLevelFeeds)
|
||||
if let folders = folders {
|
||||
for folder in folders {
|
||||
@@ -97,20 +97,20 @@ public extension Container {
|
||||
return existingFeed(withURL: url) != nil
|
||||
}
|
||||
|
||||
func has(_ feed: WebFeed) -> Bool {
|
||||
func has(_ feed: Feed) -> Bool {
|
||||
return flattenedFeeds().contains(feed)
|
||||
}
|
||||
|
||||
func existingFeed(withFeedID feedID: String) -> WebFeed? {
|
||||
func existingFeed(withFeedID feedID: String) -> Feed? {
|
||||
for feed in flattenedFeeds() {
|
||||
if feed.webFeedID == feedID {
|
||||
if feed.feedID == feedID {
|
||||
return feed
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func existingFeed(withURL url: String) -> WebFeed? {
|
||||
func existingFeed(withURL url: String) -> Feed? {
|
||||
for feed in flattenedFeeds() {
|
||||
if feed.url == url {
|
||||
return feed
|
||||
@@ -119,7 +119,7 @@ public extension Container {
|
||||
return nil
|
||||
}
|
||||
|
||||
func existingFeed(withExternalID externalID: String) -> WebFeed? {
|
||||
func existingFeed(withExternalID externalID: String) -> Feed? {
|
||||
for feed in flattenedFeeds() {
|
||||
if feed.externalID == externalID {
|
||||
return feed
|
||||
|
||||
@@ -14,7 +14,7 @@ public extension Notification.Name {
|
||||
static let FeedSettingDidChange = Notification.Name(rawValue: "FeedSettingDidChangeNotification")
|
||||
}
|
||||
|
||||
public extension WebFeed {
|
||||
public extension Feed {
|
||||
|
||||
static let FeedSettingUserInfoKey = "feedSetting"
|
||||
|
||||
@@ -30,7 +30,7 @@ public extension WebFeed {
|
||||
}
|
||||
}
|
||||
|
||||
extension WebFeed {
|
||||
extension Feed {
|
||||
|
||||
func takeSettings(from parsedFeed: ParsedFeed) {
|
||||
iconURL = parsedFeed.iconURL
|
||||
@@ -41,7 +41,7 @@ extension WebFeed {
|
||||
}
|
||||
|
||||
func postFeedSettingDidChangeNotification(_ codingKey: FeedMetadata.CodingKeys) {
|
||||
let userInfo = [WebFeed.FeedSettingUserInfoKey: codingKey.stringValue]
|
||||
let userInfo = [Feed.FeedSettingUserInfoKey: codingKey.stringValue]
|
||||
NotificationCenter.default.post(name: .FeedSettingDidChange, object: self, userInfo: userInfo)
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public extension Article {
|
||||
return manager.existingAccount(with: accountID)
|
||||
}
|
||||
|
||||
var feed: WebFeed? {
|
||||
var feed: Feed? {
|
||||
return account?.existingFeed(withFeedID: feedID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
caller.createSubscription(url: url) { result in
|
||||
@@ -418,7 +418,7 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
// This error should never happen
|
||||
guard let subscriptionID = feed.externalID else {
|
||||
@@ -445,7 +445,7 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if feed.folderRelationship?.count ?? 0 > 1 {
|
||||
deleteTagging(for: account, with: feed, from: container, completion: completion)
|
||||
} else {
|
||||
@@ -453,7 +453,7 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if from is Account {
|
||||
addFeed(for: account, with: feed, to: to, completion: completion)
|
||||
} else {
|
||||
@@ -468,9 +468,9 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
if let folder = container as? Folder, let webFeedID = Int(feed.webFeedID) {
|
||||
if let folder = container as? Folder, let webFeedID = Int(feed.feedID) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
caller.createTagging(webFeedID: webFeedID, name: folder.name ?? "") { result in
|
||||
self.refreshProgress.completeTask()
|
||||
@@ -500,7 +500,7 @@ final class FeedbinAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
if let existingFeed = account.existingFeed(withURL: feed.url) {
|
||||
account.addFeed(existingFeed, to: container) { result in
|
||||
@@ -818,7 +818,7 @@ private extension FeedbinAccountDelegate {
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.webFeedID) {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -826,7 +826,7 @@ private extension FeedbinAccountDelegate {
|
||||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.webFeedID) {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -888,7 +888,7 @@ private extension FeedbinAccountDelegate {
|
||||
|
||||
// Move any feeds not in the folder to the account
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !taggingFeedIDs.contains(feed.webFeedID) {
|
||||
if !taggingFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
clearFolderRelationship(for: feed, withFolderName: folder.name ?? "")
|
||||
account.addFeed(feed)
|
||||
@@ -896,7 +896,7 @@ private extension FeedbinAccountDelegate {
|
||||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.webFeedID }
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for tagging in groupedTaggings {
|
||||
let taggingFeedID = String(tagging.feedID)
|
||||
@@ -915,7 +915,7 @@ private extension FeedbinAccountDelegate {
|
||||
|
||||
// Remove all feeds from the account container that have a tag
|
||||
for feed in account.topLevelFeeds {
|
||||
if taggedFeedIDs.contains(feed.webFeedID) {
|
||||
if taggedFeedIDs.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -989,14 +989,14 @@ private extension FeedbinAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func clearFolderRelationship(for feed: WebFeed, withFolderName folderName: String) {
|
||||
func clearFolderRelationship(for feed: Feed, withFolderName folderName: String) {
|
||||
if var folderRelationship = feed.folderRelationship {
|
||||
folderRelationship[folderName] = nil
|
||||
feed.folderRelationship = folderRelationship
|
||||
}
|
||||
}
|
||||
|
||||
func saveFolderRelationship(for feed: WebFeed, withFolderName folderName: String, id: String) {
|
||||
func saveFolderRelationship(for feed: Feed, withFolderName folderName: String, id: String) {
|
||||
if var folderRelationship = feed.folderRelationship {
|
||||
folderRelationship[folderName] = id
|
||||
feed.folderRelationship = folderRelationship
|
||||
@@ -1005,7 +1005,7 @@ private extension FeedbinAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func decideBestFeedChoice(account: Account, url: String, name: String?, container: Container, choices: [FeedbinSubscriptionChoice], completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func decideBestFeedChoice(account: Account, url: String, name: String?, container: Container, choices: [FeedbinSubscriptionChoice], completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
var orderFound = 0
|
||||
|
||||
let feedSpecifiers: [FeedSpecifier] = choices.map { choice in
|
||||
@@ -1024,7 +1024,7 @@ private extension FeedbinAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
@@ -1057,13 +1057,13 @@ private extension FeedbinAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func initialFeedDownload( account: Account, feed: WebFeed, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func initialFeedDownload( account: Account, feed: Feed, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
// refreshArticles is being reused and will clear one of the tasks for us
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(4)
|
||||
|
||||
// Download the initial articles
|
||||
self.caller.retrieveEntries(feedID: feed.webFeedID) { result in
|
||||
self.caller.retrieveEntries(feedID: feed.feedID) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
|
||||
switch result {
|
||||
@@ -1370,7 +1370,7 @@ private extension FeedbinAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func deleteTagging(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
if let folder = container as? Folder, let feedTaggingID = feed.folderRelationship?[folder.name ?? ""] {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
@@ -1400,7 +1400,7 @@ private extension FeedbinAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func deleteSubscription(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func deleteSubscription(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
// This error should never happen
|
||||
guard let subscriptionID = feed.externalID else {
|
||||
|
||||
@@ -312,7 +312,7 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
do {
|
||||
guard let credentials = credentials else {
|
||||
@@ -344,14 +344,14 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
let folderCollectionIds = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
|
||||
guard let collectionIds = folderCollectionIds, let collectionId = collectionIds.first else {
|
||||
completion(.failure(FeedlyAccountDelegateError.unableToRenameFeed(feed.nameForDisplay, name)))
|
||||
return
|
||||
}
|
||||
|
||||
let feedId = FeedlyFeedResourceId(id: feed.webFeedID)
|
||||
let feedId = FeedlyFeedResourceId(id: feed.feedID)
|
||||
let editedNameBefore = feed.editedName
|
||||
|
||||
// Adding an existing feed updates it.
|
||||
@@ -371,14 +371,14 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
feed.editedName = name
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
do {
|
||||
guard let credentials = credentials else {
|
||||
throw FeedlyAccountDelegateError.notLoggedIn
|
||||
}
|
||||
|
||||
let resource = FeedlyFeedResourceId(id: feed.webFeedID)
|
||||
let resource = FeedlyFeedResourceId(id: feed.feedID)
|
||||
let addExistingFeed = try FeedlyAddExistingFeedOperation(account: account,
|
||||
credentials: credentials,
|
||||
resource: resource,
|
||||
@@ -401,14 +401,14 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let folder = container as? Folder, let collectionId = folder.externalID else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.unableToRemoveFeed(feed)))
|
||||
}
|
||||
}
|
||||
|
||||
caller.removeFeed(feed.webFeedID, fromCollectionWith: collectionId) { result in
|
||||
caller.removeFeed(feed.feedID, fromCollectionWith: collectionId) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
@@ -421,7 +421,7 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let from = from as? Folder, let to = to as? Folder else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.addFeedChooseFolder))
|
||||
@@ -454,7 +454,7 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
to.addFeed(feed)
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if let existingFeed = account.existingFeed(withURL: feed.url) {
|
||||
account.addFeed(existingFeed, to: container) { result in
|
||||
switch result {
|
||||
|
||||
@@ -14,11 +14,11 @@ enum FeedlyAccountDelegateError: LocalizedError {
|
||||
case unableToAddFolder(String)
|
||||
case unableToRenameFolder(String, String)
|
||||
case unableToRemoveFolder(String)
|
||||
case unableToMoveFeedBetweenFolders(WebFeed, Folder, Folder)
|
||||
case unableToMoveFeedBetweenFolders(Feed, Folder, Folder)
|
||||
case addFeedChooseFolder
|
||||
case addFeedInvalidFolder(Folder)
|
||||
case unableToRenameFeed(String, String)
|
||||
case unableToRemoveFeed(WebFeed)
|
||||
case unableToRemoveFeed(Feed)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
|
||||
@@ -26,7 +26,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
||||
private let syncUnreadIdsService: FeedlyGetStreamIdsService
|
||||
private let getStreamContentsService: FeedlyGetStreamContentsService
|
||||
private var feedResourceId: FeedlyFeedResourceId?
|
||||
var addCompletionHandler: ((Result<WebFeed, Error>) -> ())?
|
||||
var addCompletionHandler: ((Result<Feed, Error>) -> ())?
|
||||
|
||||
init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress) throws {
|
||||
|
||||
|
||||
+4
-4
@@ -35,7 +35,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Log
|
||||
for (collectionFeeds, folder) in pairs {
|
||||
let feedsInFolder = folder.topLevelFeeds
|
||||
let feedsInCollection = Set(collectionFeeds.map { $0.id })
|
||||
let feedsToRemove = feedsInFolder.filter { !feedsInCollection.contains($0.webFeedID) }
|
||||
let feedsToRemove = feedsInFolder.filter { !feedsInCollection.contains($0.feedID) }
|
||||
if !feedsToRemove.isEmpty {
|
||||
folder.removeFeeds(feedsToRemove)
|
||||
}
|
||||
@@ -43,7 +43,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Log
|
||||
}
|
||||
|
||||
// Pair each Feed with its Folder.
|
||||
var feedsAdded = Set<WebFeed>()
|
||||
var feedsAdded = Set<Feed>()
|
||||
|
||||
let feedsAndFolders = pairs
|
||||
.map({ (collectionFeeds, folder) -> [(FeedlyFeed, Folder)] in
|
||||
@@ -52,7 +52,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Log
|
||||
}
|
||||
})
|
||||
.flatMap { $0 }
|
||||
.compactMap { (collectionFeed, folder) -> (WebFeed, Folder) in
|
||||
.compactMap { (collectionFeed, folder) -> (Feed, Folder) in
|
||||
|
||||
// find an existing feed previously added to the account
|
||||
if let feed = account.existingFeed(withFeedID: collectionFeed.id) {
|
||||
@@ -73,7 +73,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Log
|
||||
return (feed, folder)
|
||||
} else {
|
||||
// find an existing feed we created below in an earlier value
|
||||
for feed in feedsAdded where feed.webFeedID == collectionFeed.id {
|
||||
for feed in feedsAdded where feed.feedID == collectionFeed.id {
|
||||
return (feed, folder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public final class Folder: FeedProtocol, Renamable, Container, Hashable {
|
||||
}
|
||||
|
||||
public weak var account: Account?
|
||||
public var topLevelFeeds: Set<WebFeed> = Set<WebFeed>()
|
||||
public var topLevelFeeds: Set<Feed> = Set<Feed>()
|
||||
public var folders: Set<Folder>? = nil // subfolders are not supported, so this is always nil
|
||||
|
||||
public var name: String? {
|
||||
@@ -101,25 +101,25 @@ public final class Folder: FeedProtocol, Renamable, Container, Hashable {
|
||||
|
||||
// MARK: Container
|
||||
|
||||
public func flattenedFeeds() -> Set<WebFeed> {
|
||||
public func flattenedFeeds() -> Set<Feed> {
|
||||
// Since sub-folders are not supported, it’s always the top-level feeds.
|
||||
return topLevelFeeds
|
||||
}
|
||||
|
||||
public func objectIsChild(_ object: AnyObject) -> Bool {
|
||||
// Folders contain Feed objects only, at least for now.
|
||||
guard let feed = object as? WebFeed else {
|
||||
guard let feed = object as? Feed else {
|
||||
return false
|
||||
}
|
||||
return topLevelFeeds.contains(feed)
|
||||
}
|
||||
|
||||
public func addFeed(_ feed: WebFeed) {
|
||||
public func addFeed(_ feed: Feed) {
|
||||
topLevelFeeds.insert(feed)
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
public func addFeeds(_ feeds: Set<WebFeed>) {
|
||||
public func addFeeds(_ feeds: Set<Feed>) {
|
||||
guard !feeds.isEmpty else {
|
||||
return
|
||||
}
|
||||
@@ -127,12 +127,12 @@ public final class Folder: FeedProtocol, Renamable, Container, Hashable {
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
public func removeFeed(_ feed: WebFeed) {
|
||||
public func removeFeed(_ feed: Feed) {
|
||||
topLevelFeeds.remove(feed)
|
||||
postChildrenDidChangeNotification()
|
||||
}
|
||||
|
||||
public func removeFeeds(_ feeds: Set<WebFeed>) {
|
||||
public func removeFeeds(_ feeds: Set<Feed>) {
|
||||
guard !feeds.isEmpty else {
|
||||
return
|
||||
}
|
||||
@@ -165,7 +165,7 @@ private extension Folder {
|
||||
unreadCount = updatedUnreadCount
|
||||
}
|
||||
|
||||
func childrenContain(_ feed: WebFeed) -> Bool {
|
||||
func childrenContain(_ feed: Feed) -> Bool {
|
||||
return topLevelFeeds.contains(feed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ final class LocalAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url urlString: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(for account: Account, url urlString: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
guard let url = URL(string: urlString) else {
|
||||
completion(.failure(LocalAccountDelegateError.invalidParameter))
|
||||
return
|
||||
@@ -129,28 +129,28 @@ final class LocalAccountDelegate: AccountDelegate, Logging {
|
||||
createRSSFeed(for: account, url: url, editedName: name, container: container, completion: completion)
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
feed.editedName = name
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
container.removeFeed(feed)
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
from.removeFeed(feed)
|
||||
to.addFeed(feed)
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
container.addFeed(feed)
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
container.addFeed(feed)
|
||||
completion(.success(()))
|
||||
}
|
||||
@@ -219,7 +219,7 @@ final class LocalAccountDelegate: AccountDelegate, Logging {
|
||||
extension LocalAccountDelegate: LocalAccountRefresherDelegate {
|
||||
|
||||
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed) {
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed) {
|
||||
refreshProgress.completeTask()
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ extension LocalAccountDelegate: LocalAccountRefresherDelegate {
|
||||
|
||||
private extension LocalAccountDelegate {
|
||||
|
||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
// We need to use a batch update here because we need to assign add the feed to the
|
||||
// container before the name has been downloaded. This will put it in the sidebar
|
||||
|
||||
@@ -14,7 +14,7 @@ import Articles
|
||||
import ArticlesDatabase
|
||||
|
||||
protocol LocalAccountRefresherDelegate {
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed)
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed)
|
||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, articleChanges: ArticleChanges, completion: @escaping () -> Void)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ final class LocalAccountRefresher {
|
||||
return DownloadSession(delegate: self)
|
||||
}()
|
||||
|
||||
public func refreshFeeds(_ feeds: Set<WebFeed>, completion: (() -> Void)? = nil) {
|
||||
public func refreshFeeds(_ feeds: Set<Feed>, completion: (() -> Void)? = nil) {
|
||||
guard !feeds.isEmpty else {
|
||||
completion?()
|
||||
return
|
||||
@@ -53,7 +53,7 @@ final class LocalAccountRefresher {
|
||||
extension LocalAccountRefresher: DownloadSessionDelegate {
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, requestForRepresentedObject representedObject: AnyObject) -> URLRequest? {
|
||||
guard let feed = representedObject as? WebFeed else {
|
||||
guard let feed = representedObject as? Feed else {
|
||||
return nil
|
||||
}
|
||||
guard let url = URL(string: feed.url) else {
|
||||
@@ -69,7 +69,7 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
|
||||
}
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, downloadDidCompleteForRepresentedObject representedObject: AnyObject, response: URLResponse?, data: Data, error: NSError?, completion: @escaping () -> Void) {
|
||||
let feed = representedObject as! WebFeed
|
||||
let feed = representedObject as! Feed
|
||||
|
||||
guard !data.isEmpty, !isSuspended else {
|
||||
completion()
|
||||
@@ -120,7 +120,7 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
|
||||
}
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, shouldContinueAfterReceivingData data: Data, representedObject: AnyObject) -> Bool {
|
||||
let feed = representedObject as! WebFeed
|
||||
let feed = representedObject as! Feed
|
||||
guard !isSuspended else {
|
||||
delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
return false
|
||||
@@ -139,17 +139,17 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
|
||||
}
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, didReceiveUnexpectedResponse response: URLResponse, representedObject: AnyObject) {
|
||||
let feed = representedObject as! WebFeed
|
||||
let feed = representedObject as! Feed
|
||||
delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
}
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, didReceiveNotModifiedResponse: URLResponse, representedObject: AnyObject) {
|
||||
let feed = representedObject as! WebFeed
|
||||
let feed = representedObject as! Feed
|
||||
delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
}
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, didDiscardDuplicateRepresentedObject representedObject: AnyObject) {
|
||||
let feed = representedObject as! WebFeed
|
||||
let feed = representedObject as! Feed
|
||||
delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ extension NewsBlurAccountDelegate {
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !newsBlurFeedIds.contains(feed.webFeedID) {
|
||||
if !newsBlurFeedIds.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !newsBlurFeedIds.contains(feed.webFeedID) {
|
||||
if !newsBlurFeedIds.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ extension NewsBlurAccountDelegate {
|
||||
|
||||
// Move any feeds not in the folder to the account
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !newsBlurFolderFeedIDs.contains(feed.webFeedID) {
|
||||
if !newsBlurFolderFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
clearFolderRelationship(for: feed, withFolderName: folder.name ?? "")
|
||||
account.addFeed(feed)
|
||||
@@ -164,7 +164,7 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.webFeedID }
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for relationship in folderRelationships {
|
||||
let folderFeedID = String(relationship.feedID)
|
||||
@@ -183,7 +183,7 @@ extension NewsBlurAccountDelegate {
|
||||
if let folderRelationships = newsBlurFolderDict[" "] {
|
||||
let newsBlurFolderFeedIDs = folderRelationships.map { String($0.feedID) }
|
||||
for feed in account.topLevelFeeds {
|
||||
if !newsBlurFolderFeedIDs.contains(feed.webFeedID) {
|
||||
if !newsBlurFolderFeedIDs.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -195,14 +195,14 @@ extension NewsBlurAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func clearFolderRelationship(for feed: WebFeed, withFolderName folderName: String) {
|
||||
func clearFolderRelationship(for feed: Feed, withFolderName folderName: String) {
|
||||
if var folderRelationship = feed.folderRelationship {
|
||||
folderRelationship[folderName] = nil
|
||||
feed.folderRelationship = folderRelationship
|
||||
}
|
||||
}
|
||||
|
||||
func saveFolderRelationship(for feed: WebFeed, withFolderName folderName: String, id: String) {
|
||||
func saveFolderRelationship(for feed: Feed, withFolderName folderName: String, id: String) {
|
||||
if var folderRelationship = feed.folderRelationship {
|
||||
folderRelationship[folderName] = id
|
||||
feed.folderRelationship = folderRelationship
|
||||
@@ -412,7 +412,7 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed(account: Account, feed: NewsBlurFeed?, name: String?, container: Container, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(account: Account, feed: NewsBlurFeed?, name: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
guard let feed = feed else {
|
||||
completion(.failure(NewsBlurError.invalidParameter))
|
||||
return
|
||||
@@ -445,10 +445,10 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func downloadFeed(account: Account, feed: WebFeed, page: Int, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func downloadFeed(account: Account, feed: Feed, page: Int, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
|
||||
caller.retrieveStories(feedID: feed.webFeedID, page: page) { result in
|
||||
caller.retrieveStories(feedID: feed.feedID, page: page) { result in
|
||||
switch result {
|
||||
case .success((let stories, _)):
|
||||
// No more stories
|
||||
@@ -484,7 +484,7 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func initialFeedDownload(account: Account, feed: WebFeed, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func initialFeedDownload(account: Account, feed: Feed, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
|
||||
// Download the initial articles
|
||||
@@ -513,7 +513,7 @@ extension NewsBlurAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func deleteFeed(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func deleteFeed(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
// This error should never happen
|
||||
guard let feedID = feed.externalID else {
|
||||
completion(.failure(NewsBlurError.invalidParameter))
|
||||
@@ -529,7 +529,7 @@ extension NewsBlurAccountDelegate {
|
||||
switch result {
|
||||
case .success:
|
||||
DispatchQueue.main.async {
|
||||
let feedID = feed.webFeedID
|
||||
let feedID = feed.feedID
|
||||
|
||||
if folderName == nil {
|
||||
account.removeFeed(feed)
|
||||
|
||||
@@ -420,7 +420,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> ()) {
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> ()) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
|
||||
let folderName = (container as? Folder)?.name
|
||||
@@ -439,7 +439,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard let feedID = feed.externalID else {
|
||||
completion(.failure(NewsBlurError.invalidParameter))
|
||||
return
|
||||
@@ -466,7 +466,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard let folder = container as? Folder else {
|
||||
DispatchQueue.main.async {
|
||||
if let account = container as? Account {
|
||||
@@ -485,11 +485,11 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
deleteFeed(for: account, with: feed, from: container, completion: completion)
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard let feedID = feed.externalID else {
|
||||
completion(.failure(NewsBlurError.invalidParameter))
|
||||
return
|
||||
@@ -516,7 +516,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
if let existingFeed = account.existingFeed(withURL: feed.url) {
|
||||
account.addFeed(existingFeed, to: container) { result in
|
||||
switch result {
|
||||
@@ -544,7 +544,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
var feedsToRestore: [WebFeed] = []
|
||||
var feedsToRestore: [Feed] = []
|
||||
for feed in folder.topLevelFeeds {
|
||||
feedsToRestore.append(feed)
|
||||
folder.topLevelFeeds.remove(feed)
|
||||
|
||||
@@ -388,7 +388,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
guard let url = URL(string: url) else {
|
||||
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
|
||||
return
|
||||
@@ -437,7 +437,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: WebFeed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
// This error should never happen
|
||||
guard let subscriptionID = feed.externalID else {
|
||||
@@ -464,7 +464,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
}
|
||||
|
||||
func removeFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let subscriptionID = feed.externalID else {
|
||||
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
|
||||
return
|
||||
@@ -494,7 +494,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if from is Account {
|
||||
addFeed(for: account, with: feed, to: to, completion: completion)
|
||||
} else {
|
||||
@@ -522,7 +522,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
if let folder = container as? Folder, let feedExternalID = feed.externalID {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
||||
caller.createTagging(subscriptionID: feedExternalID, tagName: folder.name ?? "") { result in
|
||||
@@ -552,7 +552,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func restoreFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
if let existingFeed = account.existingFeed(withURL: feed.url) {
|
||||
account.addFeed(existingFeed, to: container) { result in
|
||||
@@ -758,7 +758,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.webFeedID) {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -766,7 +766,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.webFeedID) {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
account.clearFeedMetadata(feed)
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
@@ -818,7 +818,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
|
||||
// Move any feeds not in the folder to the account
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !taggingFeedIDs.contains(feed.webFeedID) {
|
||||
if !taggingFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
clearFolderRelationship(for: feed, folderExternalID: folder.externalID)
|
||||
account.addFeed(feed)
|
||||
@@ -826,7 +826,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.webFeedID }
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for subscription in groupedTaggings {
|
||||
let taggingFeedID = subscription.feedID
|
||||
@@ -845,7 +845,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
|
||||
// Remove all feeds from the account container that have a tag
|
||||
for feed in account.topLevelFeeds {
|
||||
if taggedFeedIDs.contains(feed.webFeedID) {
|
||||
if taggedFeedIDs.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
@@ -900,13 +900,13 @@ private extension ReaderAPIAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func clearFolderRelationship(for feed: WebFeed, folderExternalID: String?) {
|
||||
func clearFolderRelationship(for feed: Feed, folderExternalID: String?) {
|
||||
guard var folderRelationship = feed.folderRelationship, let folderExternalID = folderExternalID else { return }
|
||||
folderRelationship[folderExternalID] = nil
|
||||
feed.folderRelationship = folderRelationship
|
||||
}
|
||||
|
||||
func saveFolderRelationship(for feed: WebFeed, folderExternalID: String?, feedExternalID: String) {
|
||||
func saveFolderRelationship(for feed: Feed, folderExternalID: String?, feedExternalID: String) {
|
||||
guard let folderExternalID = folderExternalID else { return }
|
||||
if var folderRelationship = feed.folderRelationship {
|
||||
folderRelationship[folderExternalID] = feedExternalID
|
||||
@@ -916,7 +916,7 @@ private extension ReaderAPIAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func createFeed( account: Account, subscription sub: ReaderAPISubscription, name: String?, container: Container, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func createFeed( account: Account, subscription sub: ReaderAPISubscription, name: String?, container: Container, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
@@ -947,11 +947,11 @@ private extension ReaderAPIAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func initialFeedDownload( account: Account, feed: WebFeed, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
func initialFeedDownload( account: Account, feed: Feed, completion: @escaping (Result<Feed, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(5)
|
||||
|
||||
// Download the initial articles
|
||||
self.caller.retrieveItemIDs(type: .allForFeed, webFeedID: feed.webFeedID) { result in
|
||||
self.caller.retrieveItemIDs(type: .allForFeed, webFeedID: feed.feedID) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
switch result {
|
||||
case .success(let articleIDs):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// WebFeed.swift
|
||||
// Feed.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Brent Simmons on 7/1/17.
|
||||
@@ -11,7 +11,7 @@ import RSCore
|
||||
import RSWeb
|
||||
import Articles
|
||||
|
||||
public final class WebFeed: FeedProtocol, Renamable, Hashable, ObservableObject {
|
||||
public final class Feed: FeedProtocol, Renamable, Hashable, ObservableObject {
|
||||
|
||||
public var defaultReadFilterType: ReadFilterType {
|
||||
return .none
|
||||
@@ -22,13 +22,13 @@ public final class WebFeed: FeedProtocol, Renamable, Hashable, ObservableObject
|
||||
assertionFailure("Expected feed.account, but got nil.")
|
||||
return nil
|
||||
}
|
||||
return ItemIdentifier.feed(accountID, webFeedID)
|
||||
return ItemIdentifier.feed(accountID, feedID)
|
||||
}
|
||||
|
||||
public weak var account: Account?
|
||||
public let url: String
|
||||
|
||||
public var webFeedID: String {
|
||||
public var feedID: String {
|
||||
get {
|
||||
return metadata.feedID
|
||||
}
|
||||
@@ -273,19 +273,19 @@ public final class WebFeed: FeedProtocol, Renamable, Hashable, ObservableObject
|
||||
// MARK: - Hashable
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(webFeedID)
|
||||
hasher.combine(feedID)
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
|
||||
public class func ==(lhs: WebFeed, rhs: WebFeed) -> Bool {
|
||||
return lhs.webFeedID == rhs.webFeedID && lhs.accountID == rhs.accountID
|
||||
public class func ==(lhs: Feed, rhs: Feed) -> Bool {
|
||||
return lhs.feedID == rhs.feedID && lhs.accountID == rhs.accountID
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - OPMLRepresentable
|
||||
|
||||
extension WebFeed: OPMLRepresentable {
|
||||
extension Feed: OPMLRepresentable {
|
||||
|
||||
public func OPMLString(indentLevel: Int, allowCustomAttributes: Bool) -> String {
|
||||
// https://github.com/brentsimmons/NetNewsWire/issues/527
|
||||
@@ -313,18 +313,18 @@ extension WebFeed: OPMLRepresentable {
|
||||
}
|
||||
}
|
||||
|
||||
extension Set where Element == WebFeed {
|
||||
extension Set where Element == Feed {
|
||||
|
||||
func webFeedIDs() -> Set<String> {
|
||||
return Set<String>(map { $0.webFeedID })
|
||||
func feedIDs() -> Set<String> {
|
||||
return Set<String>(map { $0.feedID })
|
||||
}
|
||||
|
||||
func sorted() -> Array<WebFeed> {
|
||||
return sorted(by: { (webFeed1, webFeed2) -> Bool in
|
||||
if webFeed1.nameForDisplay.localizedStandardCompare(webFeed2.nameForDisplay) == .orderedSame {
|
||||
return webFeed1.url < webFeed2.url
|
||||
func sorted() -> Array<Feed> {
|
||||
return sorted(by: { (feed1, feed2) -> Bool in
|
||||
if feed1.nameForDisplay.localizedStandardCompare(feed2.nameForDisplay) == .orderedSame {
|
||||
return feed1.url < feed2.url
|
||||
}
|
||||
return webFeed1.nameForDisplay.localizedStandardCompare(webFeed2.nameForDisplay) == .orderedAscending
|
||||
return feed1.nameForDisplay.localizedStandardCompare(feed2.nameForDisplay) == .orderedAscending
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -403,10 +403,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
||||
}
|
||||
|
||||
@MainActor @objc func webFeedSettingDidChange(_ note: Notification) {
|
||||
guard let feed = note.object as? WebFeed, let key = note.userInfo?[WebFeed.FeedSettingUserInfoKey] as? String else {
|
||||
guard let feed = note.object as? Feed, let key = note.userInfo?[Feed.FeedSettingUserInfoKey] as? String else {
|
||||
return
|
||||
}
|
||||
if key == WebFeed.FeedSettingKey.homePageURL || key == WebFeed.FeedSettingKey.faviconURL {
|
||||
if key == Feed.FeedSettingKey.homePageURL || key == Feed.FeedSettingKey.faviconURL {
|
||||
let _ = faviconDownloader.favicon(for: feed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import UserNotifications
|
||||
@IBOutlet weak var isNotifyAboutNewArticlesCheckBox: NSButton!
|
||||
@IBOutlet weak var isReaderViewAlwaysOnCheckBox: NSButton?
|
||||
|
||||
private var feed: WebFeed? {
|
||||
private var feed: Feed? {
|
||||
didSet {
|
||||
if feed != oldValue {
|
||||
updateUI()
|
||||
@@ -42,7 +42,7 @@ import UserNotifications
|
||||
var windowTitle: String = NSLocalizedString("window.title.feed-inspector", comment: "Feed Inspector")
|
||||
|
||||
func canInspect(_ objects: [Any]) -> Bool {
|
||||
return objects.count == 1 && objects.first is WebFeed
|
||||
return objects.count == 1 && objects.first is Feed
|
||||
}
|
||||
|
||||
// MARK: NSViewController
|
||||
@@ -123,7 +123,7 @@ extension WebFeedInspectorViewController: NSTextFieldDelegate {
|
||||
private extension WebFeedInspectorViewController {
|
||||
|
||||
func updateFeed() {
|
||||
guard let objects = objects, objects.count == 1, let singleFeed = objects.first as? WebFeed else {
|
||||
guard let objects = objects, objects.count == 1, let singleFeed = objects.first as? Feed else {
|
||||
feed = nil
|
||||
return
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ enum TimelineSourceMode {
|
||||
}
|
||||
}
|
||||
|
||||
if let feed = currentFeedOrFolder as? WebFeed, let noteObject = noteObject as? WebFeed {
|
||||
if let feed = currentFeedOrFolder as? Feed, let noteObject = noteObject as? Feed {
|
||||
if feed == noteObject {
|
||||
updateWindowTitle()
|
||||
return
|
||||
@@ -706,7 +706,7 @@ extension MainWindowController: TimelineContainerViewControllerDelegate {
|
||||
detailViewController?.setState(detailState, mode: mode)
|
||||
}
|
||||
|
||||
func timelineRequestedWebFeedSelection(_: TimelineContainerViewController, webFeed: WebFeed) {
|
||||
func timelineRequestedWebFeedSelection(_: TimelineContainerViewController, webFeed: Feed) {
|
||||
sidebarViewController?.selectFeed(webFeed)
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ struct PasteboardFeed: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
extension WebFeed: PasteboardWriterOwner {
|
||||
extension Feed: PasteboardWriterOwner {
|
||||
|
||||
public var pasteboardWriter: NSPasteboardWriting {
|
||||
return FeedPasteboardWriter(webFeed: self)
|
||||
@@ -162,7 +162,7 @@ extension WebFeed: PasteboardWriterOwner {
|
||||
|
||||
@objc final class FeedPasteboardWriter: NSObject, NSPasteboardWriting {
|
||||
|
||||
private let webFeed: WebFeed
|
||||
private let webFeed: Feed
|
||||
static let webFeedUTI = "com.ranchero.webFeed"
|
||||
static let webFeedUTIType = NSPasteboard.PasteboardType(rawValue: webFeedUTI)
|
||||
static let webFeedUTIInternal = "com.ranchero.NetNewsWire-Evergreen.internal.webFeed"
|
||||
@@ -170,7 +170,7 @@ extension WebFeed: PasteboardWriterOwner {
|
||||
|
||||
var containerID: ContainerIdentifier? = nil
|
||||
|
||||
init(webFeed: WebFeed) {
|
||||
init(webFeed: Feed) {
|
||||
self.webFeed = webFeed
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ extension WebFeed: PasteboardWriterOwner {
|
||||
private extension FeedPasteboardWriter {
|
||||
|
||||
var pasteboardFeed: PasteboardFeed {
|
||||
return PasteboardFeed(url: webFeed.url, feedID: webFeed.webFeedID, homePageURL: webFeed.homePageURL, name: webFeed.name, editedName: webFeed.editedName, accountID: webFeed.account?.accountID, accountType: webFeed.account?.type)
|
||||
return PasteboardFeed(url: webFeed.url, feedID: webFeed.feedID, homePageURL: webFeed.homePageURL, name: webFeed.name, editedName: webFeed.editedName, accountID: webFeed.account?.accountID, accountType: webFeed.account?.type)
|
||||
}
|
||||
|
||||
var exportDictionary: PasteboardFeedDictionary {
|
||||
|
||||
@@ -144,7 +144,7 @@ private extension SidebarOutlineDataSource {
|
||||
// Don’t allow PseudoFeed to be dragged.
|
||||
// This will have to be revisited later. For instance,
|
||||
// user-created smart feeds should be draggable, maybe.
|
||||
return node.representedObject is Folder || node.representedObject is WebFeed
|
||||
return node.representedObject is Folder || node.representedObject is Feed
|
||||
}
|
||||
|
||||
// MARK: - Drag and Drop
|
||||
@@ -257,7 +257,7 @@ private extension SidebarOutlineDataSource {
|
||||
if let folder = node.representedObject as? Folder {
|
||||
return folder.account
|
||||
}
|
||||
if let feed = node.representedObject as? WebFeed {
|
||||
if let feed = node.representedObject as? Feed {
|
||||
return feed.account
|
||||
}
|
||||
return nil
|
||||
@@ -315,7 +315,7 @@ private extension SidebarOutlineDataSource {
|
||||
return .copy // different AccountIDs means can only copy
|
||||
}
|
||||
|
||||
func copyWebFeedInAccount(_ feed: WebFeed, _ destination: Container ) {
|
||||
func copyWebFeedInAccount(_ feed: Feed, _ destination: Container ) {
|
||||
destination.account?.addFeed(feed, to: destination) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@@ -326,7 +326,7 @@ private extension SidebarOutlineDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeedInAccount(_ feed: WebFeed, _ source: Container, _ destination: Container) {
|
||||
func moveFeedInAccount(_ feed: Feed, _ source: Container, _ destination: Container) {
|
||||
BatchUpdate.shared.start()
|
||||
source.account?.moveFeed(feed, from: source, to: destination) { result in
|
||||
BatchUpdate.shared.end()
|
||||
@@ -339,7 +339,7 @@ private extension SidebarOutlineDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
func copyWebFeedBetweenAccounts(_ feed: WebFeed, _ destinationContainer: Container) {
|
||||
func copyWebFeedBetweenAccounts(_ feed: Feed, _ destinationContainer: Container) {
|
||||
guard let destinationAccount = destinationContainer.account else {
|
||||
return
|
||||
}
|
||||
@@ -514,7 +514,7 @@ private extension SidebarOutlineDataSource {
|
||||
}
|
||||
|
||||
func nodeRepresentsAnyDraggedFeed(_ node: Node, _ draggedFeeds: Set<PasteboardFeed>) -> Bool {
|
||||
guard let feed = node.representedObject as? WebFeed else {
|
||||
guard let feed = node.representedObject as? Feed else {
|
||||
return false
|
||||
}
|
||||
for draggedFeed in draggedFeeds {
|
||||
@@ -553,7 +553,7 @@ private extension SidebarOutlineDataSource {
|
||||
return account
|
||||
} else if let folder = node.representedObject as? Folder {
|
||||
return folder.account
|
||||
} else if let webFeed = node.representedObject as? WebFeed {
|
||||
} else if let webFeed = node.representedObject as? Feed {
|
||||
return webFeed.account
|
||||
} else {
|
||||
return nil
|
||||
|
||||
@@ -31,8 +31,8 @@ extension SidebarViewController {
|
||||
let object = objects.first!
|
||||
|
||||
switch object {
|
||||
case is WebFeed:
|
||||
return menuForFeed(object as! WebFeed)
|
||||
case is Feed:
|
||||
return menuForFeed(object as! Feed)
|
||||
case is Folder:
|
||||
return menuForFolder(object as! Folder)
|
||||
case is PseudoFeed:
|
||||
@@ -151,7 +151,7 @@ extension SidebarViewController {
|
||||
|
||||
@objc func renameFromContextualMenu(_ sender: Any?) {
|
||||
|
||||
guard let window = view.window, let menuItem = sender as? NSMenuItem, let object = menuItem.representedObject as? DisplayNameProvider, object is WebFeed || object is Folder else {
|
||||
guard let window = view.window, let menuItem = sender as? NSMenuItem, let object = menuItem.representedObject as? DisplayNameProvider, object is Feed || object is Folder else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ extension SidebarViewController {
|
||||
|
||||
@objc func toggleNotificationsFromContextMenu(_ sender: Any?) {
|
||||
guard let item = sender as? NSMenuItem,
|
||||
let feed = item.representedObject as? WebFeed else {
|
||||
let feed = item.representedObject as? Feed else {
|
||||
return
|
||||
}
|
||||
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
|
||||
@@ -195,7 +195,7 @@ extension SidebarViewController {
|
||||
|
||||
@objc func toggleArticleExtractorFromContextMenu(_ sender: Any?) {
|
||||
guard let item = sender as? NSMenuItem,
|
||||
let feed = item.representedObject as? WebFeed else {
|
||||
let feed = item.representedObject as? Feed else {
|
||||
return
|
||||
}
|
||||
if feed.isArticleExtractorAlwaysOn == nil { feed.isArticleExtractorAlwaysOn = false }
|
||||
@@ -228,7 +228,7 @@ extension SidebarViewController: RenameWindowControllerDelegate {
|
||||
|
||||
func renameWindowController(_ windowController: RenameWindowController, didRenameObject object: Any, withNewName name: String) {
|
||||
|
||||
if let feed = object as? WebFeed {
|
||||
if let feed = object as? Feed {
|
||||
feed.rename(to: name) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@@ -264,7 +264,7 @@ private extension SidebarViewController {
|
||||
return menu
|
||||
}
|
||||
|
||||
func menuForFeed(_ webFeed: WebFeed) -> NSMenu? {
|
||||
func menuForFeed(_ webFeed: Feed) -> NSMenu? {
|
||||
|
||||
let menu = NSMenu(title: "")
|
||||
|
||||
@@ -438,7 +438,7 @@ private extension SidebarViewController {
|
||||
|
||||
func objectIsFeedOrFolder(_ object: Any) -> Bool {
|
||||
|
||||
return object is WebFeed || object is Folder
|
||||
return object is Feed || object is Folder
|
||||
}
|
||||
|
||||
func menuItem(_ title: String, _ action: Selector, _ representedObject: Any) -> NSMenuItem {
|
||||
|
||||
@@ -197,15 +197,15 @@ protocol SidebarDelegate: AnyObject {
|
||||
}
|
||||
|
||||
@objc func webFeedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed else { return }
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? Feed else { return }
|
||||
configureCellsForRepresentedObject(webFeed)
|
||||
}
|
||||
|
||||
@objc func webFeedSettingDidChange(_ note: Notification) {
|
||||
guard let webFeed = note.object as? WebFeed, let key = note.userInfo?[WebFeed.FeedSettingUserInfoKey] as? String else {
|
||||
guard let webFeed = note.object as? Feed, let key = note.userInfo?[Feed.FeedSettingUserInfoKey] as? String else {
|
||||
return
|
||||
}
|
||||
if key == WebFeed.FeedSettingKey.homePageURL || key == WebFeed.FeedSettingKey.faviconURL {
|
||||
if key == Feed.FeedSettingKey.homePageURL || key == Feed.FeedSettingKey.faviconURL {
|
||||
configureCellsForRepresentedObject(webFeed)
|
||||
}
|
||||
}
|
||||
@@ -459,7 +459,7 @@ protocol SidebarDelegate: AnyObject {
|
||||
if isReadFiltered, let itemID = feed.itemID {
|
||||
self.treeControllerDelegate.addFilterException(itemID)
|
||||
|
||||
if let webFeed = feed as? WebFeed, let account = webFeed.account {
|
||||
if let webFeed = feed as? Feed, let account = webFeed.account {
|
||||
let parentFolder = account.sortedFolders?.first(where: { $0.objectIsChild(webFeed) })
|
||||
if let parentFolderItemID = parentFolder?.itemID {
|
||||
self.treeControllerDelegate.addFilterException(parentFolderItemID)
|
||||
@@ -532,11 +532,11 @@ private extension SidebarViewController {
|
||||
return selectedNodes.first!
|
||||
}
|
||||
|
||||
var singleSelectedWebFeed: WebFeed? {
|
||||
var singleSelectedWebFeed: Feed? {
|
||||
guard let node = singleSelectedNode else {
|
||||
return nil
|
||||
}
|
||||
return node.representedObject as? WebFeed
|
||||
return node.representedObject as? Feed
|
||||
}
|
||||
|
||||
func addAllSelectedToFilterExceptions() {
|
||||
@@ -551,8 +551,8 @@ private extension SidebarViewController {
|
||||
if folderFeed.account?.existingFolder(withID: folderFeed.folderID) != nil {
|
||||
treeControllerDelegate.addFilterException(itemID)
|
||||
}
|
||||
} else if let webFeed = feed as? WebFeed {
|
||||
if webFeed.account?.existingFeed(withFeedID: webFeed.webFeedID) != nil {
|
||||
} else if let webFeed = feed as? Feed {
|
||||
if webFeed.account?.existingFeed(withFeedID: webFeed.feedID) != nil {
|
||||
treeControllerDelegate.addFilterException(itemID)
|
||||
addParentFolderToFilterExceptions(webFeed)
|
||||
}
|
||||
@@ -752,7 +752,7 @@ private extension SidebarViewController {
|
||||
guard let webFeedID = userInfo?[ArticlePathKey.webFeedID] as? String else {
|
||||
return nil
|
||||
}
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? WebFeed)?.webFeedID == webFeedID }) {
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? Feed)?.feedID == webFeedID }) {
|
||||
return node
|
||||
}
|
||||
return nil
|
||||
@@ -779,7 +779,7 @@ private extension SidebarViewController {
|
||||
}
|
||||
|
||||
func imageFor(_ node: Node) -> IconImage? {
|
||||
if let feed = node.representedObject as? WebFeed, let feedIcon = IconImageCache.shared.imageForFeed(feed) {
|
||||
if let feed = node.representedObject as? Feed, let feedIcon = IconImageCache.shared.imageForFeed(feed) {
|
||||
return feedIcon
|
||||
}
|
||||
if let smallIconProvider = node.representedObject as? SmallIconProvider {
|
||||
@@ -869,7 +869,7 @@ private extension Node {
|
||||
if representedObject === object {
|
||||
return true
|
||||
}
|
||||
if let feed1 = object as? WebFeed, let feed2 = representedObject as? WebFeed {
|
||||
if let feed1 = object as? Feed, let feed2 = representedObject as? Feed {
|
||||
return feed1 == feed2
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -12,7 +12,7 @@ import Articles
|
||||
|
||||
protocol TimelineContainerViewControllerDelegate: AnyObject {
|
||||
func timelineSelectionDidChange(_: TimelineContainerViewController, articles: [Article]?, mode: TimelineSourceMode)
|
||||
func timelineRequestedWebFeedSelection(_: TimelineContainerViewController, webFeed: WebFeed)
|
||||
func timelineRequestedWebFeedSelection(_: TimelineContainerViewController, webFeed: Feed)
|
||||
func timelineInvalidatedRestorationState(_: TimelineContainerViewController)
|
||||
|
||||
}
|
||||
@@ -141,7 +141,7 @@ extension TimelineContainerViewController: TimelineDelegate {
|
||||
delegate?.timelineSelectionDidChange(self, articles: selectedArticles, mode: mode(for: timelineViewController))
|
||||
}
|
||||
|
||||
func timelineRequestedWebFeedSelection(_: TimelineViewController, webFeed: WebFeed) {
|
||||
func timelineRequestedWebFeedSelection(_: TimelineViewController, webFeed: Feed) {
|
||||
delegate?.timelineRequestedWebFeedSelection(self, webFeed: webFeed)
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ extension TimelineViewController {
|
||||
}
|
||||
|
||||
@objc func selectFeedInSidebarFromContextualMenu(_ sender: Any?) {
|
||||
guard let menuItem = sender as? NSMenuItem, let webFeed = menuItem.representedObject as? WebFeed else {
|
||||
guard let menuItem = sender as? NSMenuItem, let webFeed = menuItem.representedObject as? Feed else {
|
||||
return
|
||||
}
|
||||
delegate?.timelineRequestedWebFeedSelection(self, webFeed: webFeed)
|
||||
@@ -179,7 +179,7 @@ private extension TimelineViewController {
|
||||
menu.addSeparatorIfNeeded()
|
||||
|
||||
if articles.count == 1, let feed = articles.first!.feed {
|
||||
if !(representedObjects?.contains(where: { $0 as? WebFeed == feed }) ?? false) {
|
||||
if !(representedObjects?.contains(where: { $0 as? Feed == feed }) ?? false) {
|
||||
menu.addItem(selectFeedInSidebarMenuItem(feed))
|
||||
}
|
||||
if let markAllMenuItem = markAllAsReadMenuItem(feed) {
|
||||
@@ -268,13 +268,13 @@ private extension TimelineViewController {
|
||||
return menuItem(NSLocalizedString("button.title-mark-below-as-read.titlecase", comment: "Mark Below as Read"), #selector(markBelowArticlesReadFromContextualMenu(_:)), articles)
|
||||
}
|
||||
|
||||
func selectFeedInSidebarMenuItem(_ feed: WebFeed) -> NSMenuItem {
|
||||
func selectFeedInSidebarMenuItem(_ feed: Feed) -> NSMenuItem {
|
||||
let localizedMenuText = NSLocalizedString("button.title.select-in-sidebar.%@", comment: "Select “%@” in Sidebar")
|
||||
let formattedMenuText = NSString.localizedStringWithFormat(localizedMenuText as NSString, feed.nameForDisplay)
|
||||
return menuItem(formattedMenuText as String, #selector(selectFeedInSidebarFromContextualMenu(_:)), feed)
|
||||
}
|
||||
|
||||
func markAllAsReadMenuItem(_ feed: WebFeed) -> NSMenuItem? {
|
||||
func markAllAsReadMenuItem(_ feed: Feed) -> NSMenuItem? {
|
||||
guard let articlesSet = try? feed.fetchArticles() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import Account
|
||||
|
||||
protocol TimelineDelegate: AnyObject {
|
||||
func timelineSelectionDidChange(_: TimelineViewController, selectedArticles: [Article]?)
|
||||
func timelineRequestedWebFeedSelection(_: TimelineViewController, webFeed: WebFeed)
|
||||
func timelineRequestedWebFeedSelection(_: TimelineViewController, webFeed: Feed)
|
||||
func timelineInvalidatedRestorationState(_: TimelineViewController)
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
||||
return
|
||||
}
|
||||
|
||||
if let representedObjects = representedObjects, representedObjects.count == 1 && representedObjects.first is WebFeed {
|
||||
if let representedObjects = representedObjects, representedObjects.count == 1 && representedObjects.first is Feed {
|
||||
showFeedNames = {
|
||||
for article in articles {
|
||||
if !article.byline().isEmpty {
|
||||
@@ -650,7 +650,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
||||
}
|
||||
|
||||
@objc func webFeedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard showIcons, let feed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed else {
|
||||
guard showIcons, let feed = note.userInfo?[UserInfoKey.webFeed] as? Feed else {
|
||||
return
|
||||
}
|
||||
let indexesToReload = tableView.indexesOfAvailableRowsPassingTest { (row) -> Bool in
|
||||
@@ -692,7 +692,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
||||
}
|
||||
|
||||
@objc func accountDidDownloadArticles(_ note: Notification) {
|
||||
guard let feeds = note.userInfo?[Account.UserInfoKey.webFeeds] as? Set<WebFeed> else {
|
||||
guard let feeds = note.userInfo?[Account.UserInfoKey.webFeeds] as? Set<Feed> else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1317,23 +1317,23 @@ private extension TimelineViewController {
|
||||
return representedObjects?.contains(where: { $0 is Folder }) ?? false
|
||||
}
|
||||
|
||||
func representedObjectsContainsAnyWebFeed(_ webFeeds: Set<WebFeed>) -> Bool {
|
||||
func representedObjectsContainsAnyWebFeed(_ webFeeds: Set<Feed>) -> Bool {
|
||||
// Return true if there’s a match or if a folder contains (recursively) one of feeds
|
||||
|
||||
guard let representedObjects = representedObjects else {
|
||||
return false
|
||||
}
|
||||
for representedObject in representedObjects {
|
||||
if let feed = representedObject as? WebFeed {
|
||||
if let feed = representedObject as? Feed {
|
||||
for oneFeed in webFeeds {
|
||||
if feed.webFeedID == oneFeed.webFeedID || feed.url == oneFeed.url {
|
||||
if feed.feedID == oneFeed.feedID || feed.url == oneFeed.url {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
else if let folder = representedObject as? Folder {
|
||||
for oneFeed in webFeeds {
|
||||
if folder.hasFeed(with: oneFeed.webFeedID) || folder.hasFeed(withURL: oneFeed.url) {
|
||||
if folder.hasFeed(with: oneFeed.feedID) || folder.hasFeed(withURL: oneFeed.url) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ extension NSApplication : ScriptingObjectContainer {
|
||||
for 'articles of feed "The Shape of Everything" of account "On My Mac"'
|
||||
*/
|
||||
|
||||
func allWebFeeds() -> [WebFeed] {
|
||||
func allWebFeeds() -> [Feed] {
|
||||
let accounts = AccountManager.shared.activeAccounts
|
||||
let emptyFeeds:[WebFeed] = []
|
||||
return accounts.reduce(emptyFeeds) { (result, nthAccount) -> [WebFeed] in
|
||||
let emptyFeeds:[Feed] = []
|
||||
return accounts.reduce(emptyFeeds) { (result, nthAccount) -> [Feed] in
|
||||
let accountFeeds = Array(nthAccount.topLevelFeeds)
|
||||
return result + accountFeeds
|
||||
}
|
||||
@@ -91,7 +91,7 @@ extension NSApplication : ScriptingObjectContainer {
|
||||
@objc(valueInWebFeedsWithUniqueID:)
|
||||
func valueInWebFeeds(withUniqueID id:String) -> ScriptableFeed? {
|
||||
let webFeeds = self.allWebFeeds()
|
||||
guard let webFeed = webFeeds.first(where:{$0.webFeedID == id}) else { return nil }
|
||||
guard let webFeed = webFeeds.first(where:{$0.feedID == id}) else { return nil }
|
||||
return ScriptableFeed(webFeed, container:self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ import Articles
|
||||
@objc(ScriptableFeed)
|
||||
class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContainer {
|
||||
|
||||
let feed:WebFeed
|
||||
let container:ScriptingObjectContainer
|
||||
let feed: Feed
|
||||
let container: ScriptingObjectContainer
|
||||
|
||||
init (_ feed:WebFeed, container:ScriptingObjectContainer) {
|
||||
init (_ feed: Feed, container:ScriptingObjectContainer) {
|
||||
self.feed = feed
|
||||
self.container = container
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
|
||||
// but in either case it seems like the accountID would be used as the keydata, so I chose ID
|
||||
@objc(uniqueId)
|
||||
var scriptingUniqueId:Any {
|
||||
return feed.webFeedID
|
||||
return feed.feedID
|
||||
}
|
||||
|
||||
// MARK: --- ScriptingObjectContainer protocol ---
|
||||
@@ -71,7 +71,7 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
|
||||
return url
|
||||
}
|
||||
|
||||
class func scriptableFeed(_ feed:WebFeed, account:Account, folder:Folder?) -> ScriptableFeed {
|
||||
class func scriptableFeed(_ feed: Feed, account: Account, folder: Folder?) -> ScriptableFeed {
|
||||
let scriptableAccount = ScriptableAccount(account)
|
||||
if let folder = folder {
|
||||
let scriptableFolder = ScriptableFolder(folder, container:scriptableAccount)
|
||||
|
||||
@@ -54,7 +54,7 @@ class ActivityManager {
|
||||
|
||||
selectingActivity = makeSelectFeedActivity(feed: feed)
|
||||
|
||||
if let webFeed = feed as? WebFeed {
|
||||
if let webFeed = feed as? Feed {
|
||||
updateSelectingActivityFeedSearchAttributes(with: webFeed)
|
||||
}
|
||||
|
||||
@@ -135,23 +135,23 @@ class ActivityManager {
|
||||
CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: ids)
|
||||
}
|
||||
|
||||
static func cleanUp(_ webFeed: WebFeed) {
|
||||
static func cleanUp(_ webFeed: Feed) {
|
||||
CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: identifiers(for: webFeed))
|
||||
}
|
||||
#endif
|
||||
|
||||
@objc func webFeedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed, let activityFeedId = selectingActivity?.userInfo?[ArticlePathKey.webFeedID] as? String else {
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? Feed, let activityFeedId = selectingActivity?.userInfo?[ArticlePathKey.webFeedID] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
if let article = readingArticle, activityFeedId == article.webFeedID {
|
||||
if let article = readingArticle, activityFeedId == article.feedID {
|
||||
updateReadArticleSearchAttributes(with: article)
|
||||
}
|
||||
#endif
|
||||
|
||||
if activityFeedId == webFeed.webFeedID {
|
||||
if activityFeedId == webFeed.feedID {
|
||||
updateSelectingActivityFeedSearchAttributes(with: webFeed)
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ private extension ActivityManager {
|
||||
#if os(iOS)
|
||||
activity.suggestedInvocationPhrase = title
|
||||
activity.isEligibleForPrediction = true
|
||||
activity.contentAttributeSet?.relatedUniqueIdentifier = feed.feedID?.description ?? ""
|
||||
activity.contentAttributeSet?.relatedUniqueIdentifier = feed.itemID?.description ?? ""
|
||||
#endif
|
||||
|
||||
return activity
|
||||
@@ -245,7 +245,7 @@ private extension ActivityManager {
|
||||
return value?.components(separatedBy: " ").filter { $0.count > 2 } ?? []
|
||||
}
|
||||
|
||||
func updateSelectingActivityFeedSearchAttributes(with feed: WebFeed) {
|
||||
func updateSelectingActivityFeedSearchAttributes(with feed: Feed) {
|
||||
|
||||
let attributeSet = CSSearchableItemAttributeSet(itemContentType: UTType.item.identifier)
|
||||
attributeSet.title = feed.nameForDisplay
|
||||
@@ -278,15 +278,15 @@ private extension ActivityManager {
|
||||
return "account_\(folder.account!.accountID)_folder_\(folder.nameForDisplay)"
|
||||
}
|
||||
|
||||
static func identifier(for feed: WebFeed) -> String {
|
||||
return "account_\(feed.account!.accountID)_feed_\(feed.webFeedID)"
|
||||
static func identifier(for feed: Feed) -> String {
|
||||
return "account_\(feed.account!.accountID)_feed_\(feed.feedID)"
|
||||
}
|
||||
|
||||
static func identifier(for article: Article) -> String {
|
||||
return "account_\(article.accountID)_feed_\(article.feedID)_article_\(article.articleID)"
|
||||
}
|
||||
|
||||
static func identifiers(for feed: WebFeed) -> [String] {
|
||||
static func identifiers(for feed: Feed) -> [String] {
|
||||
var ids = [String]()
|
||||
ids.append(identifier(for: feed))
|
||||
if let articles = try? feed.fetchArticles() {
|
||||
|
||||
@@ -77,7 +77,7 @@ final class DeleteCommand: UndoableCommand {
|
||||
}
|
||||
|
||||
for node in nodes {
|
||||
if let _ = node.representedObject as? WebFeed {
|
||||
if let _ = node.representedObject as? Feed {
|
||||
continue
|
||||
}
|
||||
if let _ = node.representedObject as? Folder {
|
||||
@@ -98,7 +98,7 @@ private struct SidebarItemSpecifier {
|
||||
private weak var account: Account?
|
||||
private let parentFolder: Folder?
|
||||
private let folder: Folder?
|
||||
private let webFeed: WebFeed?
|
||||
private let webFeed: Feed?
|
||||
private let path: ContainerPath
|
||||
private let errorHandler: (Error) -> ()
|
||||
|
||||
@@ -118,7 +118,7 @@ private struct SidebarItemSpecifier {
|
||||
|
||||
self.parentFolder = node.parentFolder()
|
||||
|
||||
if let webFeed = node.representedObject as? WebFeed {
|
||||
if let webFeed = node.representedObject as? Feed {
|
||||
self.webFeed = webFeed
|
||||
self.folder = nil
|
||||
account = webFeed.account
|
||||
@@ -271,7 +271,7 @@ private struct DeleteActionName {
|
||||
var numberOfFolders = 0
|
||||
|
||||
for node in nodes {
|
||||
if let _ = node.representedObject as? WebFeed {
|
||||
if let _ = node.representedObject as? Feed {
|
||||
numberOfFeeds += 1
|
||||
}
|
||||
else if let _ = node.representedObject as? Folder {
|
||||
|
||||
@@ -116,11 +116,11 @@ extension Article {
|
||||
return IconImageCache.shared.imageForArticle(self)
|
||||
}
|
||||
|
||||
func iconImageUrl(webFeed: WebFeed) -> URL? {
|
||||
func iconImageUrl(webFeed: Feed) -> URL? {
|
||||
if let image = iconImage() {
|
||||
let fm = FileManager.default
|
||||
var path = fm.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
let feedID = webFeed.webFeedID.replacingOccurrences(of: "/", with: "_")
|
||||
let feedID = webFeed.feedID.replacingOccurrences(of: "/", with: "_")
|
||||
#if os(macOS)
|
||||
path.appendPathComponent(feedID + "_smallIcon.tiff")
|
||||
#else
|
||||
|
||||
@@ -25,7 +25,7 @@ extension Account: SmallIconProvider {
|
||||
}
|
||||
}
|
||||
|
||||
extension WebFeed: SmallIconProvider {
|
||||
extension Feed: SmallIconProvider {
|
||||
|
||||
var smallIcon: IconImage? {
|
||||
if let iconImage = appDelegate.faviconDownloader.favicon(for: self) {
|
||||
|
||||
@@ -45,7 +45,7 @@ final class FaviconDownloader: Logging {
|
||||
}
|
||||
|
||||
private let queue: DispatchQueue
|
||||
private var cache = [WebFeed: IconImage]() // faviconURL: RSImage
|
||||
private var cache = [Feed: IconImage]() // faviconURL: RSImage
|
||||
|
||||
struct UserInfoKey {
|
||||
static let faviconURL = "faviconURL"
|
||||
@@ -70,10 +70,10 @@ final class FaviconDownloader: Logging {
|
||||
// MARK: - API
|
||||
|
||||
func resetCache() {
|
||||
cache = [WebFeed: IconImage]()
|
||||
cache = [Feed: IconImage]()
|
||||
}
|
||||
|
||||
func favicon(for webFeed: WebFeed) -> IconImage? {
|
||||
func favicon(for webFeed: Feed) -> IconImage? {
|
||||
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
@@ -95,7 +95,7 @@ final class FaviconDownloader: Logging {
|
||||
return nil
|
||||
}
|
||||
|
||||
func faviconAsIcon(for webFeed: WebFeed) -> IconImage? {
|
||||
func faviconAsIcon(for webFeed: Feed) -> IconImage? {
|
||||
|
||||
if let image = cache[webFeed] {
|
||||
return image
|
||||
|
||||
@@ -14,7 +14,7 @@ final class FaviconGenerator {
|
||||
|
||||
private static var faviconGeneratorCache = [String: IconImage]() // feedURL: RSImage
|
||||
|
||||
static func favicon(_ webFeed: WebFeed) -> IconImage {
|
||||
static func favicon(_ webFeed: Feed) -> IconImage {
|
||||
|
||||
if let favicon = FaviconGenerator.faviconGeneratorCache[webFeed.url] {
|
||||
return favicon
|
||||
|
||||
@@ -38,7 +38,7 @@ class IconImageCache {
|
||||
if let smartFeed = feed as? PseudoFeed {
|
||||
return imageForSmartFeed(smartFeed, itemID)
|
||||
}
|
||||
if let webFeed = feed as? WebFeed, let iconImage = imageForWebFeed(webFeed, itemID) {
|
||||
if let webFeed = feed as? Feed, let iconImage = imageForWebFeed(webFeed, itemID) {
|
||||
return iconImage
|
||||
}
|
||||
if let smallIconProvider = feed as? SmallIconProvider {
|
||||
@@ -80,7 +80,7 @@ private extension IconImageCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
func imageForWebFeed(_ webFeed: WebFeed, _ itemID: ItemIdentifier) -> IconImage? {
|
||||
func imageForWebFeed(_ webFeed: Feed, _ itemID: ItemIdentifier) -> IconImage? {
|
||||
if let iconImage = webFeedIconImageCache[itemID] {
|
||||
return iconImage
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ public final class WebFeedIconDownloader {
|
||||
}()
|
||||
|
||||
private var urlsInProgress = Set<String>()
|
||||
private var cache = [WebFeed: IconImage]()
|
||||
private var waitingForFeedURLs = [String: WebFeed]()
|
||||
private var cache = [Feed: IconImage]()
|
||||
private var waitingForFeedURLs = [String: Feed]()
|
||||
|
||||
init(imageDownloader: ImageDownloader, folder: String) {
|
||||
self.imageDownloader = imageDownloader
|
||||
@@ -68,10 +68,10 @@ public final class WebFeedIconDownloader {
|
||||
}
|
||||
|
||||
func resetCache() {
|
||||
cache = [WebFeed: IconImage]()
|
||||
cache = [Feed: IconImage]()
|
||||
}
|
||||
|
||||
func icon(for feed: WebFeed) -> IconImage? {
|
||||
func icon(for feed: Feed) -> IconImage? {
|
||||
|
||||
if let cachedImage = cache[feed] {
|
||||
return cachedImage
|
||||
@@ -153,7 +153,7 @@ public final class WebFeedIconDownloader {
|
||||
|
||||
private extension WebFeedIconDownloader {
|
||||
|
||||
func icon(forHomePageURL homePageURL: String, feed: WebFeed, _ imageResultBlock: @escaping (RSImage?) -> Void) {
|
||||
func icon(forHomePageURL homePageURL: String, feed: Feed, _ imageResultBlock: @escaping (RSImage?) -> Void) {
|
||||
|
||||
if homePagesWithNoIconURLCache.contains(homePageURL) || homePagesWithUglyIcons.contains(homePageURL) {
|
||||
imageResultBlock(nil)
|
||||
@@ -168,7 +168,7 @@ private extension WebFeedIconDownloader {
|
||||
findIconURLForHomePageURL(homePageURL, feed: feed)
|
||||
}
|
||||
|
||||
func icon(forURL url: String, feed: WebFeed, _ imageResultBlock: @escaping (RSImage?) -> Void) {
|
||||
func icon(forURL url: String, feed: Feed, _ imageResultBlock: @escaping (RSImage?) -> Void) {
|
||||
waitingForFeedURLs[url] = feed
|
||||
guard let imageData = imageDownloader.image(for: url) else {
|
||||
imageResultBlock(nil)
|
||||
@@ -177,7 +177,7 @@ private extension WebFeedIconDownloader {
|
||||
RSImage.scaledForIcon(imageData, imageResultBlock: imageResultBlock)
|
||||
}
|
||||
|
||||
func postFeedIconDidBecomeAvailableNotification(_ feed: WebFeed) {
|
||||
func postFeedIconDidBecomeAvailableNotification(_ feed: Feed) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
let userInfo: [AnyHashable: Any] = [UserInfoKey.webFeed: feed]
|
||||
@@ -197,7 +197,7 @@ private extension WebFeedIconDownloader {
|
||||
homePageToIconURLCacheDirty = true
|
||||
}
|
||||
|
||||
func findIconURLForHomePageURL(_ homePageURL: String, feed: WebFeed) {
|
||||
func findIconURLForHomePageURL(_ homePageURL: String, feed: Feed) {
|
||||
|
||||
guard !urlsInProgress.contains(homePageURL) else {
|
||||
return
|
||||
@@ -214,7 +214,7 @@ private extension WebFeedIconDownloader {
|
||||
}
|
||||
}
|
||||
|
||||
func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String, feed: WebFeed) {
|
||||
func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String, feed: Feed) {
|
||||
|
||||
if let url = metadata.bestWebsiteIconURL() {
|
||||
cacheIconURL(for: homePageURL, url)
|
||||
|
||||
@@ -100,7 +100,7 @@ private extension FeedTreeControllerDelegate {
|
||||
}
|
||||
|
||||
func createNode(representedObject: Any, parent: Node) -> Node? {
|
||||
if let webFeed = representedObject as? WebFeed {
|
||||
if let webFeed = representedObject as? Feed {
|
||||
return createNode(webFeed: webFeed, parent: parent)
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ private extension FeedTreeControllerDelegate {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createNode(webFeed: WebFeed, parent: Node) -> Node {
|
||||
func createNode(webFeed: Feed, parent: Node) -> Node {
|
||||
return parent.createChildNode(webFeed)
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ final class UserNotificationManager: NSObject {
|
||||
|
||||
private extension UserNotificationManager {
|
||||
|
||||
func sendNotification(webFeed: WebFeed, article: Article) {
|
||||
func sendNotification(webFeed: Feed, article: Article) {
|
||||
let content = UNMutableNotificationContent()
|
||||
|
||||
content.title = webFeed.nameForDisplay
|
||||
@@ -61,7 +61,7 @@ private extension UserNotificationManager {
|
||||
content.subtitle = ArticleStringFormatter.truncatedTitle(article)
|
||||
}
|
||||
content.body = ArticleStringFormatter.truncatedSummary(article)
|
||||
content.threadIdentifier = webFeed.webFeedID
|
||||
content.threadIdentifier = webFeed.feedID
|
||||
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: AppAssets.notificationSoundBlipFileName))
|
||||
content.userInfo = [UserInfoKey.articlePath: article.pathUserInfo]
|
||||
content.categoryIdentifier = "NEW_ARTICLE_NOTIFICATION_CATEGORY"
|
||||
@@ -79,9 +79,9 @@ private extension UserNotificationManager {
|
||||
/// - webFeed: `WebFeed`
|
||||
/// - Returns: A `UNNotifcationAttachment` if an icon is available. Otherwise nil.
|
||||
/// - Warning: In certain scenarios, this will return the `faviconTemplateImage`.
|
||||
func thumbnailAttachment(for article: Article, webFeed: WebFeed) -> UNNotificationAttachment? {
|
||||
func thumbnailAttachment(for article: Article, webFeed: Feed) -> UNNotificationAttachment? {
|
||||
if let imageURL = article.iconImageUrl(webFeed: webFeed) {
|
||||
let thumbnail = try? UNNotificationAttachment(identifier: webFeed.webFeedID, url: imageURL, options: nil)
|
||||
let thumbnail = try? UNNotificationAttachment(identifier: webFeed.feedID, url: imageURL, options: nil)
|
||||
return thumbnail
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -13,7 +13,7 @@ import UserNotifications
|
||||
|
||||
struct WebFeedInspectorView: View {
|
||||
|
||||
var webFeed: WebFeed!
|
||||
var webFeed: Feed!
|
||||
@State private var showHomePage: Bool = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -14,7 +14,7 @@ import UniformTypeIdentifiers
|
||||
extension MasterFeedViewController: UITableViewDragDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
||||
guard let node = coordinator.nodeFor(indexPath), let webFeed = node.representedObject as? WebFeed else {
|
||||
guard let node = coordinator.nodeFor(indexPath), let webFeed = node.representedObject as? Feed else {
|
||||
return [UIDragItem]()
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
}
|
||||
|
||||
guard let sourceNode = session.localDragSession?.items.first?.localObject as? Node,
|
||||
let sourceWebFeed = sourceNode.representedObject as? WebFeed else {
|
||||
let sourceWebFeed = sourceNode.representedObject as? Feed else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
}
|
||||
}()
|
||||
|
||||
guard let destination = destinationContainer, let webFeed = dragNode.representedObject as? WebFeed else { return }
|
||||
guard let destination = destinationContainer, let webFeed = dragNode.representedObject as? Feed else { return }
|
||||
|
||||
if source.account == destination.account {
|
||||
moveFeedInAccount(feed: webFeed, sourceContainer: source, destinationContainer: destination)
|
||||
@@ -138,7 +138,7 @@ private extension MasterFeedViewController {
|
||||
return correctDestination
|
||||
}
|
||||
|
||||
func moveFeedInAccount(feed: WebFeed, sourceContainer: Container, destinationContainer: Container) {
|
||||
func moveFeedInAccount(feed: Feed, sourceContainer: Container, destinationContainer: Container) {
|
||||
guard sourceContainer !== destinationContainer else { return }
|
||||
|
||||
BatchUpdate.shared.start()
|
||||
@@ -153,7 +153,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func copyWebFeedBetweenAccounts(feed: WebFeed, sourceContainer: Container, destinationContainer: Container) {
|
||||
func copyWebFeedBetweenAccounts(feed: Feed, sourceContainer: Container, destinationContainer: Container) {
|
||||
|
||||
if let existingFeed = destinationContainer.account?.existingFeed(withURL: feed.url) {
|
||||
|
||||
|
||||
@@ -144,17 +144,17 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
}
|
||||
|
||||
@objc func webFeedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed else {
|
||||
guard let webFeed = note.userInfo?[UserInfoKey.webFeed] as? Feed else {
|
||||
return
|
||||
}
|
||||
applyToCellsForRepresentedObject(webFeed, configureIcon(_:_:))
|
||||
}
|
||||
|
||||
@objc func webFeedSettingDidChange(_ note: Notification) {
|
||||
guard let webFeed = note.object as? WebFeed, let key = note.userInfo?[WebFeed.FeedSettingUserInfoKey] as? String else {
|
||||
guard let webFeed = note.object as? Feed, let key = note.userInfo?[Feed.FeedSettingUserInfoKey] as? String else {
|
||||
return
|
||||
}
|
||||
if key == WebFeed.FeedSettingKey.homePageURL || key == WebFeed.FeedSettingKey.faviconURL {
|
||||
if key == Feed.FeedSettingKey.homePageURL || key == Feed.FeedSettingKey.faviconURL {
|
||||
configureCellsForRepresentedObject(webFeed)
|
||||
}
|
||||
}
|
||||
@@ -285,7 +285,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
renameAction.backgroundColor = UIColor.systemOrange
|
||||
actions.append(renameAction)
|
||||
|
||||
if let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed {
|
||||
if let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed {
|
||||
let moreTitle = NSLocalizedString("action.title.more", comment: "More")
|
||||
let moreAction = UIContextualAction(style: .normal, title: moreTitle) { [weak self] (action, view, completion) in
|
||||
|
||||
@@ -340,7 +340,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? FeedProtocol else {
|
||||
return nil
|
||||
}
|
||||
if feed is WebFeed {
|
||||
if feed is Feed {
|
||||
return makeWebFeedContextMenu(indexPath: indexPath, includeDeleteRename: true)
|
||||
} else if feed is Folder {
|
||||
return makeFolderContextMenu(indexPath: indexPath)
|
||||
@@ -850,7 +850,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func configureIcon(_ cell: MasterFeedTableViewCell, _ indexPath: IndexPath) {
|
||||
guard let node = coordinator.nodeFor(indexPath), let feed = node.representedObject as? FeedProtocol, let feedID = feed.feedID else {
|
||||
guard let node = coordinator.nodeFor(indexPath), let feed = node.representedObject as? FeedProtocol, let feedID = feed.itemID else {
|
||||
return
|
||||
}
|
||||
cell.iconImage = IconImageCache.shared.imageFor(feedID)
|
||||
@@ -872,7 +872,7 @@ private extension MasterFeedViewController {
|
||||
if let node = coordinator.nodeFor(indexPath),
|
||||
let representedFeed = representedObject as? FeedProtocol,
|
||||
let candidate = node.representedObject as? FeedProtocol,
|
||||
representedFeed.feedID == candidate.feedID {
|
||||
representedFeed.itemID == candidate.itemID {
|
||||
completion(cell, indexPath)
|
||||
}
|
||||
}
|
||||
@@ -906,7 +906,7 @@ private extension MasterFeedViewController {
|
||||
if let folder = node.representedObject as? Folder {
|
||||
return folder.account
|
||||
}
|
||||
if let feed = node.representedObject as? WebFeed {
|
||||
if let feed = node.representedObject as? Feed {
|
||||
return feed.account
|
||||
}
|
||||
return nil
|
||||
@@ -1062,7 +1062,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func copyFeedPageAction(indexPath: IndexPath) -> UIAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed,
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
let url = URL(string: webFeed.url) else {
|
||||
return nil
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func copyFeedPageAlertAction(indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed,
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
let url = URL(string: webFeed.url) else {
|
||||
return nil
|
||||
}
|
||||
@@ -1089,7 +1089,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func copyHomePageAction(indexPath: IndexPath) -> UIAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed,
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
let homePageURL = webFeed.homePageURL,
|
||||
let url = URL(string: homePageURL) else {
|
||||
return nil
|
||||
@@ -1103,7 +1103,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func copyHomePageAlertAction(indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed,
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
let homePageURL = webFeed.homePageURL,
|
||||
let url = URL(string: homePageURL) else {
|
||||
return nil
|
||||
@@ -1118,7 +1118,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func markAllAsReadAlertAction(indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed,
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
webFeed.unreadCount > 0,
|
||||
let articles = try? webFeed.fetchArticles(), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||
return nil
|
||||
@@ -1157,7 +1157,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func getInfoAction(indexPath: IndexPath) -> UIAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed else {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1185,7 +1185,7 @@ private extension MasterFeedViewController {
|
||||
}
|
||||
|
||||
func getInfoAlertAction(indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? WebFeed else {
|
||||
guard let webFeed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1442,7 +1442,7 @@ private extension MasterFeedViewController {
|
||||
return
|
||||
}
|
||||
|
||||
if let webFeed = feed as? WebFeed {
|
||||
if let webFeed = feed as? Feed {
|
||||
webFeed.rename(to: name) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
@@ -1517,7 +1517,7 @@ private extension MasterFeedViewController {
|
||||
|
||||
if let folder = deleteNode.representedObject as? Folder {
|
||||
ActivityManager.cleanUp(folder)
|
||||
} else if let feed = deleteNode.representedObject as? WebFeed {
|
||||
} else if let feed = deleteNode.representedObject as? Feed {
|
||||
ActivityManager.cleanUp(feed)
|
||||
}
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
titleView.iconView.iconImage = coordinator.timelineIconImage
|
||||
}
|
||||
|
||||
guard let feed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed else {
|
||||
guard let feed = note.userInfo?[UserInfoKey.webFeed] as? Feed else {
|
||||
return
|
||||
}
|
||||
tableView.indexPathsForVisibleRows?.forEach { indexPath in
|
||||
@@ -564,7 +564,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
|
||||
let prototypeID = "prototype"
|
||||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, dateArrived: Date())
|
||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||
|
||||
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Prototype Feed Name", byline: nil, iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize, hideSeparator: false)
|
||||
|
||||
@@ -640,7 +640,7 @@ private extension MasterTimelineViewController {
|
||||
titleView.label.text = coordinator.timelineFeed?.nameForDisplay
|
||||
updateTitleUnreadCount()
|
||||
|
||||
if coordinator.timelineFeed is WebFeed {
|
||||
if coordinator.timelineFeed is Feed {
|
||||
titleView.buttonize()
|
||||
titleView.addGestureRecognizer(feedTapGestureRecognizer)
|
||||
} else {
|
||||
|
||||
+31
-31
@@ -45,11 +45,11 @@ struct FeedNode: Hashable {
|
||||
guard let feed = node.representedObject as? FeedProtocol else { return nil }
|
||||
|
||||
self.node = node
|
||||
self.feedID = feed.feedID!
|
||||
self.itemID = feed.itemID!
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(feedID)
|
||||
hasher.combine(itemID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
var isReadArticlesFiltered: Bool {
|
||||
if let feedID = timelineFeed?.feedID, let readFilterEnabled = readFilterEnabledTable[feedID] {
|
||||
if let feedID = timelineFeed?.itemID, let readFilterEnabled = readFilterEnabledTable[feedID] {
|
||||
return readFilterEnabled
|
||||
} else {
|
||||
return timelineDefaultReadFilterType != .none
|
||||
@@ -513,7 +513,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
@objc func userDidAddFeed(_ notification: Notification) {
|
||||
guard let webFeed = notification.userInfo?[UserInfoKey.webFeed] as? WebFeed else {
|
||||
guard let webFeed = notification.userInfo?[UserInfoKey.webFeed] as? Feed else {
|
||||
return
|
||||
}
|
||||
discloseWebFeed(webFeed, animations: [.scroll, .navigation])
|
||||
@@ -525,7 +525,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
@objc func accountDidDownloadArticles(_ note: Notification) {
|
||||
guard let feeds = note.userInfo?[Account.UserInfoKey.webFeeds] as? Set<WebFeed> else {
|
||||
guard let feeds = note.userInfo?[Account.UserInfoKey.webFeeds] as? Set<Feed> else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -605,7 +605,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
func toggleReadArticlesFilter() {
|
||||
guard let feedID = timelineFeed?.feedID else {
|
||||
guard let feedID = timelineFeed?.itemID else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1119,15 +1119,15 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
markArticlesWithUndo([article], statusKey: .starred, flag: !article.status.starred, directlyMarked: true)
|
||||
}
|
||||
|
||||
func timelineFeedIsEqualTo(_ feed: WebFeed) -> Bool {
|
||||
guard let timelineFeed = timelineFeed as? WebFeed else {
|
||||
func timelineFeedIsEqualTo(_ feed: Feed) -> Bool {
|
||||
guard let timelineFeed = timelineFeed as? Feed else {
|
||||
return false
|
||||
}
|
||||
|
||||
return timelineFeed == feed
|
||||
}
|
||||
|
||||
func discloseWebFeed(_ webFeed: WebFeed, initialLoad: Bool = false, animations: Animations = [], completion: (() -> Void)? = nil) {
|
||||
func discloseWebFeed(_ webFeed: Feed, initialLoad: Bool = false, animations: Animations = [], completion: (() -> Void)? = nil) {
|
||||
if isSearching {
|
||||
masterTimelineViewController?.hideSearch()
|
||||
}
|
||||
@@ -1144,10 +1144,10 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
markExpanded(parentFolder)
|
||||
}
|
||||
|
||||
if let webFeedFeedID = webFeed.feedID {
|
||||
if let webFeedFeedID = webFeed.itemID {
|
||||
self.treeControllerDelegate.addFilterException(webFeedFeedID)
|
||||
}
|
||||
if let parentFolderFeedID = parentFolder?.feedID {
|
||||
if let parentFolderFeedID = parentFolder?.itemID {
|
||||
self.treeControllerDelegate.addFilterException(parentFolderFeedID)
|
||||
}
|
||||
|
||||
@@ -1184,7 +1184,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
func showFeedInspector() {
|
||||
let timelineWebFeed = timelineFeed as? WebFeed
|
||||
let timelineWebFeed = timelineFeed as? Feed
|
||||
let articleFeed = currentArticle?.feed
|
||||
guard let feed = timelineWebFeed ?? articleFeed else {
|
||||
return
|
||||
@@ -1192,7 +1192,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
showFeedInspector(for: feed)
|
||||
}
|
||||
|
||||
func showFeedInspector(for feed: WebFeed) {
|
||||
func showFeedInspector(for feed: Feed) {
|
||||
|
||||
let hosting = UIHostingController(rootView: InjectedNavigationView(injectedView: WebFeedInspectorView(webFeed: feed)))
|
||||
|
||||
@@ -1233,7 +1233,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
|
||||
func homePageURLForFeed(_ indexPath: IndexPath) -> URL? {
|
||||
guard let node = nodeFor(indexPath),
|
||||
let feed = node.representedObject as? WebFeed,
|
||||
let feed = node.representedObject as? Feed,
|
||||
let homePageURL = feed.homePageURL,
|
||||
let url = URL(string: homePageURL) else {
|
||||
return nil
|
||||
@@ -1487,15 +1487,15 @@ private extension SceneCoordinator {
|
||||
}
|
||||
|
||||
func addToFilterExeptionsIfNecessary(_ feed: FeedProtocol?) {
|
||||
if isReadFeedsFiltered, let feedID = feed?.feedID {
|
||||
if isReadFeedsFiltered, let feedID = feed?.itemID {
|
||||
if feed is SmartFeed {
|
||||
treeControllerDelegate.addFilterException(feedID)
|
||||
} else if let folderFeed = feed as? Folder {
|
||||
if folderFeed.account?.existingFolder(withID: folderFeed.folderID) != nil {
|
||||
treeControllerDelegate.addFilterException(feedID)
|
||||
}
|
||||
} else if let webFeed = feed as? WebFeed {
|
||||
if webFeed.account?.existingFeed(withWebFeedID: webFeed.webFeedID) != nil {
|
||||
} else if let webFeed = feed as? Feed {
|
||||
if webFeed.account?.existingFeed(withFeedID: webFeed.feedID) != nil {
|
||||
treeControllerDelegate.addFilterException(feedID)
|
||||
addParentFolderToFilterExceptions(webFeed)
|
||||
}
|
||||
@@ -1506,7 +1506,7 @@ private extension SceneCoordinator {
|
||||
func addParentFolderToFilterExceptions(_ feed: FeedProtocol) {
|
||||
guard let node = treeController.rootNode.descendantNodeRepresentingObject(feed as AnyObject),
|
||||
let folder = node.parent?.representedObject as? Folder,
|
||||
let folderFeedID = folder.feedID else {
|
||||
let folderFeedID = folder.itemID else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1516,7 +1516,7 @@ private extension SceneCoordinator {
|
||||
func addShadowTableToFilterExceptions() {
|
||||
for section in shadowTable {
|
||||
for feedNode in section.feedNodes {
|
||||
if let feed = feedNode.node.representedObject as? FeedProtocol, let feedID = feed.feedID {
|
||||
if let feed = feedNode.node.representedObject as? FeedProtocol, let feedID = feed.itemID {
|
||||
treeControllerDelegate.addFilterException(feedID)
|
||||
}
|
||||
}
|
||||
@@ -1651,7 +1651,7 @@ private extension SceneCoordinator {
|
||||
func shadowTableContains(_ feed: FeedProtocol) -> Bool {
|
||||
for section in shadowTable {
|
||||
for feedNode in section.feedNodes {
|
||||
if let nodeFeed = feedNode.node.representedObject as? FeedProtocol, nodeFeed.feedID == feed.feedID {
|
||||
if let nodeFeed = feedNode.node.representedObject as? FeedProtocol, nodeFeed.itemID == feed.itemID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1676,7 +1676,7 @@ private extension SceneCoordinator {
|
||||
|
||||
func updateShowNamesAndIcons() {
|
||||
|
||||
if timelineFeed is WebFeed {
|
||||
if timelineFeed is Feed {
|
||||
showFeedNames = {
|
||||
for article in articles {
|
||||
if !article.byline().isEmpty {
|
||||
@@ -2016,7 +2016,7 @@ private extension SceneCoordinator {
|
||||
if !unsortedArticleIDs.contains(article.articleID) {
|
||||
updatedArticles.insert(article)
|
||||
}
|
||||
if article.account?.existingFeed(withWebFeedID: article.webFeedID) == nil {
|
||||
if article.account?.existingFeed(withFeedID: article.feedID) == nil {
|
||||
updatedArticles.remove(article)
|
||||
}
|
||||
}
|
||||
@@ -2089,19 +2089,19 @@ private extension SceneCoordinator {
|
||||
return false
|
||||
}
|
||||
|
||||
func timelineFetcherContainsAnyFeed(_ feeds: Set<WebFeed>) -> Bool {
|
||||
func timelineFetcherContainsAnyFeed(_ feeds: Set<Feed>) -> Bool {
|
||||
|
||||
// Return true if there’s a match or if a folder contains (recursively) one of feeds
|
||||
|
||||
if let feed = timelineFeed as? WebFeed {
|
||||
if let feed = timelineFeed as? Feed {
|
||||
for oneFeed in feeds {
|
||||
if feed.webFeedID == oneFeed.webFeedID || feed.url == oneFeed.url {
|
||||
if feed.feedID == oneFeed.feedID || feed.url == oneFeed.url {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if let folder = timelineFeed as? Folder {
|
||||
for oneFeed in feeds {
|
||||
if folder.hasFeed(with: oneFeed.webFeedID) || folder.hasFeed(withURL: oneFeed.url) {
|
||||
if folder.hasFeed(with: oneFeed.feedID) || folder.hasFeed(withURL: oneFeed.url) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -2172,10 +2172,10 @@ private extension SceneCoordinator {
|
||||
}
|
||||
})
|
||||
|
||||
case .webFeed(let accountID, let webFeedID):
|
||||
case .feed(let accountID, let webFeedID):
|
||||
guard let accountNode = findAccountNode(accountID: accountID),
|
||||
let account = accountNode.representedObject as? Account,
|
||||
let webFeed = account.existingFeed(withWebFeedID: webFeedID) else {
|
||||
let webFeed = account.existingFeed(withFeedID: webFeedID) else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2204,7 +2204,7 @@ private extension SceneCoordinator {
|
||||
return
|
||||
}
|
||||
|
||||
guard let webFeed = account.existingFeed(withWebFeedID: webFeedID) else {
|
||||
guard let webFeed = account.existingFeed(withFeedID: webFeedID) else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2233,7 +2233,7 @@ private extension SceneCoordinator {
|
||||
}
|
||||
return found
|
||||
|
||||
case .webFeed:
|
||||
case .feed:
|
||||
let found = selectFeedAndArticle(itemIdentifier: itemIdentifier, articleID: articleID, isShowingExtractedArticle: isShowingExtractedArticle, articleWindowScrollY: articleWindowScrollY)
|
||||
if found {
|
||||
treeControllerDelegate.addFilterException(itemIdentifier)
|
||||
@@ -2267,7 +2267,7 @@ private extension SceneCoordinator {
|
||||
}
|
||||
|
||||
func findWebFeedNode(webFeedID: String, beginningAt startingNode: Node) -> Node? {
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? WebFeed)?.webFeedID == webFeedID }) {
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? Feed)?.feedID == webFeedID }) {
|
||||
return node
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -18,9 +18,9 @@ struct NewArticleNotificationsView: View, Logging {
|
||||
var body: some View {
|
||||
List(activeAccounts, id: \.accountID) { account in
|
||||
Section(header: Text(account.nameForDisplay)) {
|
||||
ForEach(sortedWebFeedsForAccount(account), id: \.webFeedID) { feed in
|
||||
ForEach(sortedWebFeedsForAccount(account), id: \.feedID) { feed in
|
||||
WebFeedToggle(webfeed: feed)
|
||||
.id(feed.webFeedID)
|
||||
.id(feed.feedID)
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text("navigation.title.new-article-notifications", comment: "New Article Notifications"))
|
||||
@@ -44,12 +44,12 @@ struct NewArticleNotificationsView: View, Logging {
|
||||
}
|
||||
})
|
||||
.onReceive(NotificationCenter.default.publisher(for: .WebFeedIconDidBecomeAvailable), perform: { notification in
|
||||
guard let webFeed = notification.userInfo?[UserInfoKey.webFeed] as? WebFeed else { return }
|
||||
guard let webFeed = notification.userInfo?[UserInfoKey.webFeed] as? Feed else { return }
|
||||
webFeed.objectWillChange.send()
|
||||
})
|
||||
}
|
||||
|
||||
private func sortedWebFeedsForAccount(_ account: Account) -> [WebFeed] {
|
||||
private func sortedWebFeedsForAccount(_ account: Account) -> [Feed] {
|
||||
return Array(account.flattenedFeeds()).sorted(by: { $0.nameForDisplay.caseInsensitiveCompare($1.nameForDisplay) == .orderedAscending })
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ struct NewArticleNotificationsView: View, Logging {
|
||||
|
||||
fileprivate struct WebFeedToggle: View {
|
||||
|
||||
@ObservedObject var webfeed: WebFeed
|
||||
@ObservedObject var webfeed: Feed
|
||||
|
||||
var body: some View {
|
||||
Toggle(isOn: Binding(
|
||||
@@ -67,7 +67,7 @@ fileprivate struct WebFeedToggle: View {
|
||||
Label {
|
||||
Text(webfeed.nameForDisplay)
|
||||
} icon: {
|
||||
Image(uiImage: IconImageCache.shared.imageFor(webfeed.feedID!)!.image)
|
||||
Image(uiImage: IconImageCache.shared.imageFor(webfeed.itemID!)!.image)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.cornerRadius(4)
|
||||
|
||||
Reference in New Issue
Block a user