mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Merge branch 'main' into ios-ui-settings-localised
# Conflicts: # NetNewsWire.xcodeproj/project.pbxproj # Shared/Timer/AccountRefreshTimer.swift # iOS/Account/ReaderAPIAccountViewController.swift
This commit is contained in:
@@ -286,30 +286,6 @@ blockquote {
|
||||
border-top: 1px solid var(--header-table-border-color);
|
||||
}
|
||||
|
||||
/* Twitter */
|
||||
|
||||
.twitterAvatar {
|
||||
vertical-align: middle;
|
||||
border-radius: 4px;
|
||||
height: 1.7em;
|
||||
width: 1.7em;
|
||||
}
|
||||
|
||||
.twitterUsername {
|
||||
line-height: 1.2;
|
||||
margin-left: 4px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.twitterScreenName {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
.twitterTimestamp {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
/* Newsfoot theme for light mode (default) */
|
||||
.newsfoot-footnote-popover {
|
||||
background: #ccc;
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ArticleTheme: Equatable {
|
||||
static let defaultTheme = ArticleTheme()
|
||||
static let nnwThemeSuffix = ".nnwtheme"
|
||||
|
||||
private static let defaultThemeName = NSLocalizedString("Default", comment: "Default")
|
||||
private static let defaultThemeName = "NetNewsWire"
|
||||
private static let unknownValue = NSLocalizedString("Unknown", comment: "Unknown Value")
|
||||
|
||||
let path: String?
|
||||
|
||||
@@ -77,6 +77,10 @@ public class ArticleThemeDownloader: Logging {
|
||||
private func findThemeFile(in searchPath: String) -> String? {
|
||||
if let directoryContents = FileManager.default.enumerator(atPath: searchPath) {
|
||||
while let file = directoryContents.nextObject() as? String {
|
||||
if file.hasPrefix("__MACOSX/") {
|
||||
logger.debug("Ignoring theme file in __MACOSX folder.")
|
||||
continue
|
||||
}
|
||||
if file.hasSuffix(".nnwtheme") {
|
||||
return file
|
||||
}
|
||||
|
||||
@@ -80,11 +80,13 @@ final class ArticleThemesManager: NSObject, NSFilePresenter, Logging, Observable
|
||||
}
|
||||
|
||||
func presentedSubitemDidChange(at url: URL) {
|
||||
themeNames = buildThemeNames()
|
||||
do {
|
||||
currentTheme = try articleThemeWithThemeName(currentThemeName)
|
||||
} catch {
|
||||
appDelegate.presentThemeImportError(error)
|
||||
if url.lastPathComponent.localizedCaseInsensitiveContains("nnwtheme") {
|
||||
themeNames = buildThemeNames()
|
||||
do {
|
||||
currentTheme = try articleThemeWithThemeName(currentThemeName)
|
||||
} catch {
|
||||
appDelegate.presentThemeImportError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ enum ExtensionPointIdentifer: Hashable {
|
||||
case marsEdit
|
||||
case microblog
|
||||
#endif
|
||||
case twitter(String)
|
||||
case reddit(String)
|
||||
|
||||
var extensionPointType: ExtensionPoint.Type {
|
||||
@@ -26,8 +25,6 @@ enum ExtensionPointIdentifer: Hashable {
|
||||
case .microblog:
|
||||
return SendToMicroBlogCommand.self
|
||||
#endif
|
||||
case .twitter:
|
||||
return TwitterFeedProvider.self
|
||||
case .reddit:
|
||||
return RedditFeedProvider.self
|
||||
}
|
||||
@@ -45,11 +42,6 @@ enum ExtensionPointIdentifer: Hashable {
|
||||
"type": "microblog"
|
||||
]
|
||||
#endif
|
||||
case .twitter(let screenName):
|
||||
return [
|
||||
"type": "twitter",
|
||||
"screenName": screenName
|
||||
]
|
||||
case .reddit(let username):
|
||||
return [
|
||||
"type": "reddit",
|
||||
@@ -68,9 +60,6 @@ enum ExtensionPointIdentifer: Hashable {
|
||||
case "microblog":
|
||||
self = ExtensionPointIdentifer.microblog
|
||||
#endif
|
||||
case "twitter":
|
||||
guard let screenName = userInfo["screenName"] as? String else { return nil }
|
||||
self = ExtensionPointIdentifer.twitter(screenName)
|
||||
case "reddit":
|
||||
guard let username = userInfo["username"] as? String else { return nil }
|
||||
self = ExtensionPointIdentifer.reddit(username)
|
||||
@@ -87,9 +76,6 @@ enum ExtensionPointIdentifer: Hashable {
|
||||
case .microblog:
|
||||
hasher.combine("microblog")
|
||||
#endif
|
||||
case .twitter(let screenName):
|
||||
hasher.combine("twitter")
|
||||
hasher.combine(screenName)
|
||||
case .reddit(let username):
|
||||
hasher.combine("reddit")
|
||||
hasher.combine(username)
|
||||
|
||||
@@ -69,16 +69,12 @@ final class ExtensionPointManager: FeedProviderManagerDelegate {
|
||||
return activeExtensionPoints.values.compactMap({ return $0 as? FeedProvider })
|
||||
}
|
||||
|
||||
var isTwitterEnabled: Bool {
|
||||
return activeExtensionPoints.values.contains(where: { $0 is TwitterFeedProvider })
|
||||
}
|
||||
|
||||
var isRedditEnabled: Bool {
|
||||
return activeExtensionPoints.values.contains(where: { $0 is RedditFeedProvider })
|
||||
}
|
||||
|
||||
init() {
|
||||
possibleExtensionPointTypes = [TwitterFeedProvider.self, RedditFeedProvider.self]
|
||||
possibleExtensionPointTypes = [RedditFeedProvider.self]
|
||||
loadExtensionPoints()
|
||||
}
|
||||
|
||||
@@ -121,12 +117,6 @@ private extension ExtensionPointManager {
|
||||
|
||||
func extensionPoint(for extensionPointType: ExtensionPoint.Type, tokenSuccess: OAuthSwift.TokenSuccess?, completion: @escaping (Result<ExtensionPoint, Error>) -> Void) {
|
||||
switch extensionPointType {
|
||||
case is TwitterFeedProvider.Type:
|
||||
if let tokenSuccess = tokenSuccess, let twitter = TwitterFeedProvider(tokenSuccess: tokenSuccess) {
|
||||
completion(.success(twitter))
|
||||
} else {
|
||||
completion(.failure(ExtensionPointManagerError.unableToCreate))
|
||||
}
|
||||
case is RedditFeedProvider.Type:
|
||||
if let tokenSuccess = tokenSuccess {
|
||||
RedditFeedProvider.create(tokenSuccess: tokenSuccess) { result in
|
||||
@@ -147,8 +137,6 @@ private extension ExtensionPointManager {
|
||||
|
||||
func extensionPoint(for extensionPointID: ExtensionPointIdentifer) -> ExtensionPoint? {
|
||||
switch extensionPointID {
|
||||
case .twitter(let screenName):
|
||||
return TwitterFeedProvider(screenName: screenName)
|
||||
case .reddit(let username):
|
||||
return RedditFeedProvider(username: username)
|
||||
#if os(macOS)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<title>Default Feeds</title>
|
||||
</head>
|
||||
<body>
|
||||
<<<<<<< HEAD
|
||||
<outline text="Colossal" title="Colossal" type="rss" version="RSS" htmlUrl="https://www.thisiscolossal.com/" xmlUrl="https://www.thisiscolossal.com/feed/"/>
|
||||
<outline text="Becky Hansmeyer" title="Becky Hansmeyer" type="rss" version="RSS" htmlUrl="https://beckyhansmeyer.com" xmlUrl="https://beckyhansmeyer.com/feed/"/>
|
||||
<outline text="Maurice Parker" title="Maurice Parker" type="rss" version="RSS" htmlUrl="https://vincode.io/" xmlUrl="https://vincode.io/feed.xml"/>
|
||||
@@ -21,5 +22,17 @@
|
||||
<outline text="Craig Hockenberry" title="Craig Hockenberry" type="rss" version="RSS" htmlUrl="https://furbo.org/" xmlUrl="https://furbo.org/feed/json"/>
|
||||
<outline text="Rose Orchard" title="Rose Orchard" type="rss" version="RSS" htmlUrl="https://rosemaryorchard.com/" xmlUrl="https://rosemaryorchard.com/feed.xml"/>
|
||||
<outline text="Michael Tsai" title="Michael Tsai" type="rss" version="RSS" htmlUrl="https://mjtsai.com/blog/" xmlUrl="https://mjtsai.com/blog/feed/"/>
|
||||
=======
|
||||
<outline text="BBC News - World" title="BBC News - World" type="rss" version="RSS" htmlUrl="https://www.bbc.com/news" xmlUrl="https://feeds.bbci.co.uk/news/world/rss.xml"/>
|
||||
<outline text="Becky Hansmeyer" title="Becky Hansmeyer" type="rss" version="RSS" htmlUrl="https://beckyhansmeyer.com" xmlUrl="https://beckyhansmeyer.com/feed/"/>
|
||||
<outline text="Colossal" title="Colossal" type="rss" version="RSS" htmlUrl="https://www.thisiscolossal.com/" xmlUrl="https://www.thisiscolossal.com/feed/"/>
|
||||
<outline text="Daring Fireball" title="Daring Fireball" type="rss" version="RSS" htmlUrl="https://daringfireball.net/" xmlUrl="https://daringfireball.net/feeds/json"/>
|
||||
<outline text="inessential" title="inessential" type="rss" version="RSS" htmlUrl="https://inessential.com/" xmlUrl="https://inessential.com/feed.json"/>
|
||||
<outline text="Jason Kottke" title="Jason Kottke" type="rss" version="RSS" htmlUrl="https://kottke.org/" xmlUrl="http://feeds.kottke.org/json"/>
|
||||
<outline text="Maurice Parker" title="Maurice Parker" type="rss" version="RSS" htmlUrl="https://vincode.io/" xmlUrl="https://vincode.io/feed.xml"/>
|
||||
<outline text="NetNewsWire Blog" title="NetNewsWire Blog" type="rss" version="RSS" htmlUrl="https://nnw.ranchero.com/" xmlUrl="https://nnw.ranchero.com/feed.json"/>
|
||||
<outline text="One Foot Tsunami" title="One Foot Tsunami" type="rss" version="RSS" htmlUrl="https://onefoottsunami.com/" xmlUrl="https://onefoottsunami.com/feed/json/"/>
|
||||
<outline text="Six Colors" title="Six Colors" type="rss" version="RSS" htmlUrl="https://sixcolors.com/" xmlUrl="https://feedpress.me/sixcolors?type=xml"/>
|
||||
>>>>>>> ios-release
|
||||
</body>
|
||||
</opml>
|
||||
|
||||
@@ -3,24 +3,26 @@
|
||||
body {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
word-wrap: break-word;
|
||||
max-width: 44em;
|
||||
background-color: #FBF0D9;
|
||||
color: #704214;
|
||||
background-color: rgb(248, 241, 227);
|
||||
color: rgb(79, 50, 28);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-shadow: 0 1px rgba(255, 255, 255, 2);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.feedlink {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.headerTable {
|
||||
width: 100%;
|
||||
height: 68px;
|
||||
#nnwImageIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.systemMessage {
|
||||
@@ -37,34 +39,48 @@ a:hover {
|
||||
--header-color: rgba(0, 0, 0, 0.5);
|
||||
--body-code-color: #704214;
|
||||
--system-message-color: #704214;
|
||||
--feedlink-color: rgba(255, 0, 0, 0.6);
|
||||
--feedlink-color: #704214;
|
||||
--article-title-color: #704214;
|
||||
--article-date-color: rgba(0, 0, 0, 0.5);
|
||||
--table-cell-border-color: lightgray;
|
||||
--primary-accent-color: #43350E;
|
||||
--secondary-accent-color: #43350E;
|
||||
--primary-accent-color: #43350e;
|
||||
--secondary-accent-color: #43350e;
|
||||
--block-quote-border-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
body a, body a:visited, body a * {
|
||||
body a,
|
||||
body a:visited,
|
||||
body a * {
|
||||
color: var(--secondary-accent-color);
|
||||
}
|
||||
|
||||
|
||||
body .headerTable {
|
||||
body > header {
|
||||
border-bottom: 1px solid var(--header-table-border-color);
|
||||
color: var(--header-color);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
body .header {
|
||||
body > header a,
|
||||
body > header a:link,
|
||||
body > header a:visited {
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
body .header a:link, .header a:visited {
|
||||
body > header .headerTable {
|
||||
width: 100%;
|
||||
}
|
||||
body > header .headerTable td,
|
||||
body > header .headerTable th {
|
||||
color: var(--header-color);
|
||||
padding: 0.2em;
|
||||
border: none;
|
||||
font-family: sans-serif;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
body > header .headerTable td.avatar {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
body code, body pre {
|
||||
body code,
|
||||
body pre {
|
||||
color: var(--body-code-color);
|
||||
}
|
||||
|
||||
@@ -72,15 +88,11 @@ body > .systemMessage {
|
||||
color: var(--system-message-color);
|
||||
}
|
||||
|
||||
.headerContainer a:link, .headerContainer a:visited {
|
||||
text-decoration: none;
|
||||
.headerContainer a:link,
|
||||
.headerContainer a:visited {
|
||||
color: var(--feedlink-color);
|
||||
}
|
||||
|
||||
.headerContainer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.avatar img {
|
||||
border-radius: 4px;
|
||||
}
|
||||
@@ -97,44 +109,35 @@ body > .systemMessage {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.articleTitle a:link, .articleTitle a:visited {
|
||||
.articleTitle a:link,
|
||||
.articleTitle a:visited {
|
||||
text-decoration: none;
|
||||
color: var(--article-title-color);
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.articleTitle a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.articleDateline {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.articleDateline a:link, .articleDateline a:visited {
|
||||
.articleDateline a:link,
|
||||
.articleDateline a:visited {
|
||||
text-decoration: none;
|
||||
color: var(--article-date-color);
|
||||
}
|
||||
|
||||
.articleDateline a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.articleDatelineTitle {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.articleDatelineTitle a:link, .articleDatelineTitle a:visited {
|
||||
.articleDatelineTitle a:link,
|
||||
.articleDatelineTitle a:visited {
|
||||
text-decoration: none;
|
||||
color: var(--article-title-color);
|
||||
}
|
||||
|
||||
.articleDatelineTitle a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.externalLink {
|
||||
margin-bottom: 5px;
|
||||
font-style: italic;
|
||||
@@ -144,14 +147,11 @@ body > .systemMessage {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.externalLink a:link, .externalLink a:visited {
|
||||
.externalLink a:link,
|
||||
.externalLink a:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.externalLink a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.articleBody {
|
||||
margin-top: 20px;
|
||||
line-height: 1.6em;
|
||||
@@ -177,17 +177,14 @@ pre {
|
||||
line-height: 1.4286em;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
code,
|
||||
pre {
|
||||
font-family: "SF Mono", Menlo, "Courier New", Courier, monospace;
|
||||
font-size: 1em;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: -0.027em;
|
||||
-webkit-hyphens: none;
|
||||
}
|
||||
|
||||
pre code {
|
||||
letter-spacing: -.027em;
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
|
||||
.nnw-overflow {
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -209,7 +206,8 @@ pre code {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.nnw-overflow td, .nnw-overflow th {
|
||||
.nnw-overflow td,
|
||||
.nnw-overflow th {
|
||||
-webkit-hyphens: none;
|
||||
word-break: normal;
|
||||
border: 1px solid var(--table-cell-border-color);
|
||||
@@ -222,7 +220,10 @@ pre code {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.nnw-overflow :matches(thead, tbody, tfoot):last-child > tr:last-child :matches(td, th) {
|
||||
.nnw-overflow
|
||||
:matches(thead, tbody, tfoot):last-child
|
||||
> tr:last-child
|
||||
:matches(td, th) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@@ -235,16 +236,16 @@ pre code {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
img, figure, video, div, object {
|
||||
img,
|
||||
figure,
|
||||
video,
|
||||
div,
|
||||
object {
|
||||
max-width: 100%;
|
||||
height: auto !important;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
iframe {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
@@ -340,12 +341,12 @@ blockquote {
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-arrow {
|
||||
background: #FBF0D9;
|
||||
background: #fbf0d9;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-inner {
|
||||
background: #FBF0D9;
|
||||
background: #fbf0d9;
|
||||
}
|
||||
|
||||
body a.footnote,
|
||||
@@ -364,7 +365,6 @@ a.footnote:hover,
|
||||
|
||||
/* iOS Specific */
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
|
||||
body {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 20px;
|
||||
@@ -374,7 +374,7 @@ a.footnote:hover,
|
||||
word-break: break-word;
|
||||
-webkit-hyphens: auto;
|
||||
-webkit-text-size-adjust: none;
|
||||
font: Georgia;
|
||||
font-family: Charter, Georgia, sans-serif;
|
||||
font-size: [[font-size]]px;
|
||||
}
|
||||
|
||||
@@ -386,18 +386,16 @@ a.footnote:hover,
|
||||
.nnw-overflow table {
|
||||
border: 1px solid var(--secondary-accent-color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* macOS Specific */
|
||||
@supports not (-webkit-touch-callout: none) {
|
||||
|
||||
body {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 64px;
|
||||
padding-left: 48px;
|
||||
padding-right: 48px;
|
||||
font-family: Georgia;
|
||||
font-family: Charter, Georgia, sans-serif;
|
||||
}
|
||||
|
||||
.smallText {
|
||||
@@ -428,5 +426,4 @@ a.footnote:hover,
|
||||
.nnw-overflow table {
|
||||
border: 1px solid var(--primary-accent-color);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<header class="headerContainer">
|
||||
<table cellpadding=0 cellspacing=0 border=0 class="headerTable">
|
||||
<table class="headerTable">
|
||||
<tr>
|
||||
<td class="header leftAlign"><a class="feedlink" href="[[feed_link]]">[[feed_link_title]]</a><br />[[byline]]</td>
|
||||
<td class="header rightAlign avatar"><img id="nnwImageIcon" src="[[avatar_src]]" height=48 width=48 /></td>
|
||||
<td class="leftAlign"><a class="feedlink" href="[[feed_link]]">[[feed_link_title]]</a><br />[[byline]]</td>
|
||||
<td class="rightAlign avatar"><img id="nnwImageIcon" src="[[avatar_src]]" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</header>
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
%{
|
||||
import os
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
secrets = ['MERCURY_CLIENT_ID', 'MERCURY_CLIENT_SECRET', 'FEEDLY_CLIENT_ID', 'FEEDLY_CLIENT_SECRET', 'TWITTER_CONSUMER_KEY', 'TWITTER_CONSUMER_SECRET', 'REDDIT_CONSUMER_KEY', 'INOREADER_APP_ID', 'INOREADER_APP_KEY']
|
||||
=======
|
||||
secrets = ['FEED_WRANGLER_KEY', 'MERCURY_CLIENT_ID', 'MERCURY_CLIENT_SECRET', 'FEEDLY_CLIENT_ID', 'FEEDLY_CLIENT_SECRET', 'REDDIT_CONSUMER_KEY', 'INOREADER_APP_ID', 'INOREADER_APP_KEY']
|
||||
>>>>>>> mac-release
|
||||
=======
|
||||
secrets = ['FEED_WRANGLER_KEY', 'MERCURY_CLIENT_ID', 'MERCURY_CLIENT_SECRET', 'FEEDLY_CLIENT_ID', 'FEEDLY_CLIENT_SECRET', 'REDDIT_CONSUMER_KEY', 'INOREADER_APP_ID', 'INOREADER_APP_KEY']
|
||||
>>>>>>> ios-release
|
||||
|
||||
def chunks(seq, size):
|
||||
return (seq[i:(i + size)] for i in range(0, len(seq), size))
|
||||
|
||||
@@ -35,5 +35,10 @@ struct SearchFeedDelegate: SmartFeedDelegate {
|
||||
func fetchUnreadCount(for: Account, completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
// TODO: after 5.0
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
fatalError("Function not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -35,4 +35,9 @@ struct SearchTimelineFeedDelegate: SmartFeedDelegate {
|
||||
func fetchUnreadCount(for: Account, completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
// TODO: after 5.0
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
fatalError("Function not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ final class SmartFeed: PseudoFeed {
|
||||
}
|
||||
#endif
|
||||
|
||||
private let delegate: SmartFeedDelegate
|
||||
public let delegate: SmartFeedDelegate
|
||||
private var unreadCounts = [String: Int]()
|
||||
|
||||
init(delegate: SmartFeedDelegate) {
|
||||
@@ -95,6 +95,10 @@ extension SmartFeed: ArticleFetcher {
|
||||
return try delegate.fetchUnreadArticles()
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
return try delegate.fetchUnreadArticlesBetween(before: before, after: after)
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock) {
|
||||
delegate.fetchUnreadArticlesAsync(completion)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ extension SmartFeedDelegate {
|
||||
return try fetchArticles().unreadArticles()
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
return try AccountManager.shared.fetchUnreadArticlesBetween(limit: nil, before: before, after: after)
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock) {
|
||||
fetchArticlesAsync{ articleSetResult in
|
||||
switch articleSetResult {
|
||||
|
||||
@@ -29,4 +29,8 @@ struct StarredFeedDelegate: SmartFeedDelegate {
|
||||
func fetchUnreadCount(for account: Account, completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
account.fetchUnreadCountForStarredArticles(completion)
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
return try AccountManager.shared.fetchUnreadArticlesBetween(limit: nil, before: before, after: after).filter({ $0.status.starred })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,10 @@ extension UnreadFeed: ArticleFetcher {
|
||||
return try AccountManager.shared.fetchArticles(fetchType)
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesBetween(before: Date? = nil, after: Date? = nil) throws -> Set<Article> {
|
||||
return try AccountManager.shared.fetchUnreadArticlesBetween(limit: nil, before: before, after: after)
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock) {
|
||||
AccountManager.shared.fetchArticlesAsync(fetchType, completion)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class WidgetDataEncoder {
|
||||
|
||||
@available(iOS 14, *)
|
||||
private func encodeWidgetData(completion: @escaping (WidgetData?) -> Void) {
|
||||
var dispatchGroup = DispatchGroup()
|
||||
let dispatchGroup = DispatchGroup()
|
||||
var groupError: Error? = nil
|
||||
|
||||
var unread = [LatestArticle]()
|
||||
@@ -143,9 +143,9 @@ public final class WidgetDataEncoder {
|
||||
let latestData = WidgetData(currentUnreadCount: SmartFeedsController.shared.unreadFeed.unreadCount,
|
||||
currentTodayCount: SmartFeedsController.shared.todayFeed.unreadCount,
|
||||
currentStarredCount: (try? AccountManager.shared.fetchCountForStarredArticles()) ?? 0,
|
||||
unreadArticles: unread,
|
||||
starredArticles: starred,
|
||||
todayArticles:today,
|
||||
unreadArticles: unread.sorted(by: { $0.pubDate > $1.pubDate }),
|
||||
starredArticles: starred.sorted(by: { $0.pubDate > $1.pubDate }),
|
||||
todayArticles:today.sorted(by: { $0.pubDate > $1.pubDate }),
|
||||
lastUpdateTime: Date())
|
||||
completion(latestData)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user