Create SmartFeed class. It’s for Unread and Starred pseudo-feeds — and will also be used later on by predicate-based smart feeds.
This commit is contained in:
parent
9f415dfab7
commit
9c571271e6
|
@ -13,6 +13,8 @@
|
|||
842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */; };
|
||||
842E45E71ED8C747000A8B52 /* DB5.plist in Resources */ = {isa = PBXBuildFile; fileRef = 842E45E61ED8C747000A8B52 /* DB5.plist */; };
|
||||
84513F901FAA63950023A1A9 /* FeedListControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84513F8F1FAA63950023A1A9 /* FeedListControlsView.swift */; };
|
||||
845EE7B11FC2366500854A1F /* StarredFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845EE7B01FC2366500854A1F /* StarredFeedDelegate.swift */; };
|
||||
845EE7C11FC2488C00854A1F /* SmartFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845EE7C01FC2488C00854A1F /* SmartFeed.swift */; };
|
||||
845F52ED1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */; };
|
||||
846E773D1F6EF67A00A165E2 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846E773A1F6EF5D700A165E2 /* Account.framework */; };
|
||||
846E773E1F6EF67A00A165E2 /* Account.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 846E773A1F6EF5D700A165E2 /* Account.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
|
@ -99,7 +101,7 @@
|
|||
84F204DE1FAACB8B0076E152 /* FeedListTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DD1FAACB8B0076E152 /* FeedListTimelineViewController.swift */; };
|
||||
84F204E01FAACBB30076E152 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; };
|
||||
84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */; };
|
||||
84F2D5381FC22FCC00998D64 /* TodayFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5361FC22FCB00998D64 /* TodayFeed.swift */; };
|
||||
84F2D5381FC22FCC00998D64 /* TodayFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */; };
|
||||
84F2D53A1FC2308B00998D64 /* UnreadFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5391FC2308B00998D64 /* UnreadFeed.swift */; };
|
||||
84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; };
|
||||
84FB9A301EDCD6C4003D53B9 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
|
@ -400,6 +402,8 @@
|
|||
842E45E61ED8C747000A8B52 /* DB5.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = DB5.plist; path = Evergreen/Resources/DB5.plist; sourceTree = "<group>"; };
|
||||
84513F8F1FAA63950023A1A9 /* FeedListControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListControlsView.swift; sourceTree = "<group>"; };
|
||||
845B14A51FC2299E0013CF92 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
845EE7B01FC2366500854A1F /* StarredFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarredFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
845EE7C01FC2488C00854A1F /* SmartFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartFeed.swift; sourceTree = "<group>"; };
|
||||
845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedPasteboardWriter.swift; sourceTree = "<group>"; };
|
||||
846E77161F6EF5D000A165E2 /* Database.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Database.xcodeproj; path = Frameworks/Database/Database.xcodeproj; sourceTree = "<group>"; };
|
||||
846E77301F6EF5D600A165E2 /* Account.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Account.xcodeproj; path = Frameworks/Account/Account.xcodeproj; sourceTree = "<group>"; };
|
||||
|
@ -479,7 +483,7 @@
|
|||
84F204DD1FAACB8B0076E152 /* FeedListTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListTimelineViewController.swift; sourceTree = "<group>"; };
|
||||
84F204DF1FAACBB30076E152 /* ArticleArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleArray.swift; sourceTree = "<group>"; };
|
||||
84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PseudoFeed.swift; sourceTree = "<group>"; };
|
||||
84F2D5361FC22FCB00998D64 /* TodayFeed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodayFeed.swift; sourceTree = "<group>"; };
|
||||
84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodayFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
84F2D5391FC2308B00998D64 /* UnreadFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadFeed.swift; sourceTree = "<group>"; };
|
||||
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Frameworks/Vendor/Sparkle.framework; sourceTree = SOURCE_ROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
@ -900,8 +904,10 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */,
|
||||
84F2D5361FC22FCB00998D64 /* TodayFeed.swift */,
|
||||
84F2D5391FC2308B00998D64 /* UnreadFeed.swift */,
|
||||
845EE7C01FC2488C00854A1F /* SmartFeed.swift */,
|
||||
84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */,
|
||||
845EE7B01FC2366500854A1F /* StarredFeedDelegate.swift */,
|
||||
);
|
||||
name = PseudoFeeds;
|
||||
path = Evergreen/PseudoFeeds;
|
||||
|
@ -1285,6 +1291,7 @@
|
|||
849A97661ED9EB96007D329B /* SidebarViewController.swift in Sources */,
|
||||
849A97641ED9EB96007D329B /* SidebarOutlineView.swift in Sources */,
|
||||
84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */,
|
||||
845EE7C11FC2488C00854A1F /* SmartFeed.swift in Sources */,
|
||||
84702AA41FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift in Sources */,
|
||||
849A979F1ED9F130007D329B /* SidebarCell.swift in Sources */,
|
||||
849A97651ED9EB96007D329B /* SidebarTreeControllerDelegate.swift in Sources */,
|
||||
|
@ -1299,10 +1306,11 @@
|
|||
849A978A1ED9ECEF007D329B /* ArticleStylesManager.swift in Sources */,
|
||||
849A97791ED9EC04007D329B /* TimelineStringUtilities.swift in Sources */,
|
||||
84F204CE1FAACB660076E152 /* FeedListViewController.swift in Sources */,
|
||||
845EE7B11FC2366500854A1F /* StarredFeedDelegate.swift in Sources */,
|
||||
849A97981ED9EFAA007D329B /* Node-Extensions.swift in Sources */,
|
||||
849A97531ED9EAC0007D329B /* AddFeedController.swift in Sources */,
|
||||
849A97831ED9EC63007D329B /* StatusBarView.swift in Sources */,
|
||||
84F2D5381FC22FCC00998D64 /* TodayFeed.swift in Sources */,
|
||||
84F2D5381FC22FCC00998D64 /* TodayFeedDelegate.swift in Sources */,
|
||||
849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */,
|
||||
849A97921ED9EF65007D329B /* IndeterminateProgressWindowController.swift in Sources */,
|
||||
849A97801ED9EC42007D329B /* DetailViewController.swift in Sources */,
|
||||
|
|
|
@ -97,7 +97,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
|||
|
||||
currentTheme = themeLoader.defaultTheme
|
||||
|
||||
pseudoFeeds = [TodayFeed(), UnreadFeed()]
|
||||
let todayFeed = SmartFeed(delegate: TodayFeedDelegate())
|
||||
let unreadFeed = UnreadFeed()
|
||||
let starredFeed = SmartFeed(delegate: StarredFeedDelegate())
|
||||
pseudoFeeds = [todayFeed, unreadFeed, starredFeed]
|
||||
|
||||
createAndShowMainWindow()
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TodayFeed.swift
|
||||
// SmartFeed.swift
|
||||
// Evergreen
|
||||
//
|
||||
// Created by Brent Simmons on 11/19/17.
|
||||
|
@ -7,12 +7,22 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import Data
|
||||
import Account
|
||||
|
||||
final class TodayFeed: PseudoFeed {
|
||||
protocol SmartFeedDelegate: DisplayNameProvider {
|
||||
|
||||
let nameForDisplay = NSLocalizedString("Today", comment: "Today pseudo-feed title")
|
||||
func fetchUnreadCount(for: Account, callback: @escaping (Int) -> Void)
|
||||
}
|
||||
|
||||
final class SmartFeed: PseudoFeed {
|
||||
|
||||
var nameForDisplay: String {
|
||||
get {
|
||||
return delegate.nameForDisplay
|
||||
}
|
||||
}
|
||||
|
||||
var unreadCount = 0 {
|
||||
didSet {
|
||||
|
@ -22,11 +32,13 @@ final class TodayFeed: PseudoFeed {
|
|||
}
|
||||
}
|
||||
|
||||
private let delegate: SmartFeedDelegate
|
||||
private var timer: Timer?
|
||||
private var unreadCounts = [Account: Int]()
|
||||
|
||||
init() {
|
||||
init(delegate: SmartFeedDelegate) {
|
||||
|
||||
self.delegate = delegate
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
||||
startTimer() // Fetch unread count at startup
|
||||
}
|
||||
|
@ -39,13 +51,13 @@ final class TodayFeed: PseudoFeed {
|
|||
}
|
||||
}
|
||||
|
||||
private extension TodayFeed {
|
||||
private extension SmartFeed {
|
||||
|
||||
// MARK: - Unread Counts
|
||||
|
||||
private func fetchUnreadCount(for account: Account) {
|
||||
|
||||
account.fetchUnreadCountForToday { (accountUnreadCount) in
|
||||
delegate.fetchUnreadCount(for: account) { (accountUnreadCount) in
|
||||
self.unreadCounts[account] = accountUnreadCount
|
||||
self.updateUnreadCount()
|
||||
}
|
||||
|
@ -82,10 +94,9 @@ private extension TodayFeed {
|
|||
|
||||
stopTimer()
|
||||
|
||||
timer = Timer.scheduledTimer(withTimeInterval: TodayFeed.fetchCoalescingDelay, repeats: false, block: { (timer) in
|
||||
timer = Timer.scheduledTimer(withTimeInterval: SmartFeed.fetchCoalescingDelay, repeats: false, block: { (timer) in
|
||||
self.fetchUnreadCounts()
|
||||
self.stopTimer()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// StarredFeedDelegate.swift
|
||||
// Evergreen
|
||||
//
|
||||
// Created by Brent Simmons on 11/19/17.
|
||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Data
|
||||
import Account
|
||||
|
||||
|
||||
struct StarredFeedDelegate: SmartFeedDelegate {
|
||||
|
||||
let nameForDisplay = NSLocalizedString("Starred", comment: "Starred pseudo-feed title")
|
||||
|
||||
func fetchUnreadCount(for account: Account, callback: @escaping (Int) -> Void) {
|
||||
|
||||
account.fetchUnreadCountForStarredArticles(callback)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// TodayFeedDelegate.swift
|
||||
// Evergreen
|
||||
//
|
||||
// Created by Brent Simmons on 11/19/17.
|
||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Data
|
||||
import Account
|
||||
|
||||
struct TodayFeedDelegate: SmartFeedDelegate {
|
||||
|
||||
let nameForDisplay = NSLocalizedString("Today", comment: "Today pseudo-feed title")
|
||||
|
||||
func fetchUnreadCount(for account: Account, callback: @escaping (Int) -> Void) {
|
||||
|
||||
account.fetchUnreadCountForToday(callback)
|
||||
}
|
||||
}
|
||||
|
|
@ -330,6 +330,11 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
database.fetchUnreadCount(for: flattenedFeeds(), since: startOfToday, callback: callback)
|
||||
}
|
||||
|
||||
public func fetchUnreadCountForStarredArticles(_ callback: @escaping (Int) -> Void) {
|
||||
|
||||
database.fetchStarredAndUnreadCount(for: flattenedFeeds(), callback: callback)
|
||||
}
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@objc func downloadProgressDidChange(_ note: Notification) {
|
||||
|
|
|
@ -164,6 +164,23 @@ final class ArticlesTable: DatabaseTable {
|
|||
}
|
||||
}
|
||||
|
||||
func fetchStarredAndUnreadCount(_ feeds: Set<Feed>, _ callback: @escaping (Int) -> Void) {
|
||||
|
||||
let feedIDs = feeds.feedIDs()
|
||||
queue.fetch { (database) in
|
||||
|
||||
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(feedIDs.count))!
|
||||
let sql = "select count(*) from articles natural join statuses where feedID in \(placeholders) and read=0 and starred=1 and userDeleted=0;"
|
||||
let parameters = Array(feedIDs) as [Any]
|
||||
|
||||
let unreadCount = self.numberWithSQLAndParameters(sql, parameters, in: database)
|
||||
|
||||
DispatchQueue.main.async() {
|
||||
callback(unreadCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Status
|
||||
|
||||
func mark(_ articles: Set<Article>, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set<ArticleStatus>? {
|
||||
|
|
|
@ -15,3 +15,5 @@ CREATE INDEX if not EXISTS articles_feedID_index on articles (feedID);
|
|||
CREATE INDEX if not EXISTS tags_tagName_index on tags (tagName COLLATE NOCASE);
|
||||
|
||||
CREATE INDEX if not EXISTS statuses_read_index on statuses (read);
|
||||
CREATE INDEX if not EXISTS statuses_starred_index on statuses (starred);
|
||||
|
||||
|
|
|
@ -66,6 +66,11 @@ public final class Database {
|
|||
articlesTable.fetchUnreadCount(feeds, since, callback)
|
||||
}
|
||||
|
||||
public func fetchStarredAndUnreadCount(for feeds: Set<Feed>, callback: @escaping (Int) -> Void) {
|
||||
|
||||
articlesTable.fetchStarredAndUnreadCount(feeds, callback)
|
||||
}
|
||||
|
||||
// MARK: - Saving and Updating Articles
|
||||
|
||||
public func update(feed: Feed, parsedFeed: ParsedFeed, completion: @escaping UpdateArticlesWithFeedCompletionBlock) {
|
||||
|
|
Loading…
Reference in New Issue