Fix lint issues.
This commit is contained in:
parent
bbef99f2d3
commit
10f4351904
@ -25,7 +25,7 @@ protocol ArticleExtractorDelegate {
|
|||||||
|
|
||||||
class ArticleExtractor {
|
class ArticleExtractor {
|
||||||
|
|
||||||
private var dataTask: URLSessionDataTask? = nil
|
private var dataTask: URLSessionDataTask?
|
||||||
|
|
||||||
var state: ArticleExtractorState!
|
var state: ArticleExtractorState!
|
||||||
var article: ExtractedArticle?
|
var article: ExtractedArticle?
|
||||||
@ -56,7 +56,7 @@ class ArticleExtractor {
|
|||||||
|
|
||||||
state = .processing
|
state = .processing
|
||||||
|
|
||||||
dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
|
dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
|
||||||
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
@ -230,8 +230,7 @@ private extension ArticleRenderer {
|
|||||||
components.path = article.articleID
|
components.path = article.articleID
|
||||||
if let imageIconURLString = components.string {
|
if let imageIconURLString = components.string {
|
||||||
d["avatar_src"] = imageIconURLString
|
d["avatar_src"] = imageIconURLString
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
d["avatar_src"] = ""
|
d["avatar_src"] = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,27 +282,22 @@ private extension ArticleRenderer {
|
|||||||
}
|
}
|
||||||
isFirstAuthor = false
|
isFirstAuthor = false
|
||||||
|
|
||||||
var authorEmailAddress: String? = nil
|
var authorEmailAddress: String?
|
||||||
if let emailAddress = author.emailAddress, !(emailAddress.contains("noreply@") || emailAddress.contains("no-reply@")) {
|
if let emailAddress = author.emailAddress, !(emailAddress.contains("noreply@") || emailAddress.contains("no-reply@")) {
|
||||||
authorEmailAddress = emailAddress
|
authorEmailAddress = emailAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if let emailAddress = authorEmailAddress, emailAddress.contains(" ") {
|
if let emailAddress = authorEmailAddress, emailAddress.contains(" ") {
|
||||||
byline += emailAddress // probably name plus email address
|
byline += emailAddress // probably name plus email address
|
||||||
}
|
} else if let name = author.name, let url = author.url {
|
||||||
else if let name = author.name, let url = author.url {
|
|
||||||
byline += name.htmlByAddingLink(url)
|
byline += name.htmlByAddingLink(url)
|
||||||
}
|
} else if let name = author.name, let emailAddress = authorEmailAddress {
|
||||||
else if let name = author.name, let emailAddress = authorEmailAddress {
|
|
||||||
byline += "\(name) <\(emailAddress)>"
|
byline += "\(name) <\(emailAddress)>"
|
||||||
}
|
} else if let name = author.name {
|
||||||
else if let name = author.name {
|
|
||||||
byline += name
|
byline += name
|
||||||
}
|
} else if let emailAddress = authorEmailAddress {
|
||||||
else if let emailAddress = authorEmailAddress {
|
|
||||||
byline += "<\(emailAddress)>" // TODO: mailto link
|
byline += "<\(emailAddress)>" // TODO: mailto link
|
||||||
}
|
} else if let url = author.url {
|
||||||
else if let url = author.url {
|
|
||||||
byline += String.htmlWithLink(url)
|
byline += String.htmlWithLink(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,4 +349,3 @@ private extension Article {
|
|||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,10 +29,9 @@ public class ArticleThemeDownloader {
|
|||||||
createDownloadDirectoryIfRequired()
|
createDownloadDirectoryIfRequired()
|
||||||
let movedFileLocation = try moveTheme(from: location)
|
let movedFileLocation = try moveTheme(from: location)
|
||||||
let unzippedFileLocation = try unzipFile(at: movedFileLocation)
|
let unzippedFileLocation = try unzipFile(at: movedFileLocation)
|
||||||
NotificationCenter.default.post(name: .didEndDownloadingTheme, object: nil, userInfo: ["url" : unzippedFileLocation])
|
NotificationCenter.default.post(name: .didEndDownloadingTheme, object: nil, userInfo: ["url": unzippedFileLocation])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Creates `Application Support/NetNewsWire/Downloads` if needed.
|
/// Creates `Application Support/NetNewsWire/Downloads` if needed.
|
||||||
private func createDownloadDirectoryIfRequired() {
|
private func createDownloadDirectoryIfRequired() {
|
||||||
try? FileManager.default.createDirectory(at: downloadDirectory(), withIntermediateDirectories: true, attributes: nil)
|
try? FileManager.default.createDirectory(at: downloadDirectory(), withIntermediateDirectories: true, attributes: nil)
|
||||||
@ -68,7 +67,6 @@ public class ArticleThemeDownloader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Performs a deep search of the unzipped directory to find the theme file.
|
/// Performs a deep search of the unzipped directory to find the theme file.
|
||||||
/// - Parameter searchPath: directory to search
|
/// - Parameter searchPath: directory to search
|
||||||
/// - Returns: optional `String`
|
/// - Returns: optional `String`
|
||||||
|
@ -126,7 +126,7 @@ final class ArticleThemesManager: NSObject, NSFilePresenter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK : Private
|
// MARK: Private
|
||||||
|
|
||||||
private extension ArticleThemesManager {
|
private extension ArticleThemesManager {
|
||||||
|
|
||||||
|
@ -20,11 +20,11 @@ final class DeleteCommand: UndoableCommand {
|
|||||||
var redoActionName: String {
|
var redoActionName: String {
|
||||||
return undoActionName
|
return undoActionName
|
||||||
}
|
}
|
||||||
let errorHandler: (Error) -> ()
|
let errorHandler: (Error) -> Void
|
||||||
|
|
||||||
private let itemSpecifiers: [SidebarItemSpecifier]
|
private let itemSpecifiers: [SidebarItemSpecifier]
|
||||||
|
|
||||||
init?(nodesToDelete: [Node], treeController: TreeController? = nil, undoManager: UndoManager, errorHandler: @escaping (Error) -> ()) {
|
init?(nodesToDelete: [Node], treeController: TreeController? = nil, undoManager: UndoManager, errorHandler: @escaping (Error) -> Void) {
|
||||||
|
|
||||||
guard DeleteCommand.canDelete(nodesToDelete) else {
|
guard DeleteCommand.canDelete(nodesToDelete) else {
|
||||||
return nil
|
return nil
|
||||||
@ -38,7 +38,7 @@ final class DeleteCommand: UndoableCommand {
|
|||||||
self.undoManager = undoManager
|
self.undoManager = undoManager
|
||||||
self.errorHandler = errorHandler
|
self.errorHandler = errorHandler
|
||||||
|
|
||||||
let itemSpecifiers = nodesToDelete.compactMap{ SidebarItemSpecifier(node: $0, errorHandler: errorHandler) }
|
let itemSpecifiers = nodesToDelete.compactMap { SidebarItemSpecifier(node: $0, errorHandler: errorHandler) }
|
||||||
guard !itemSpecifiers.isEmpty else {
|
guard !itemSpecifiers.isEmpty else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ final class DeleteCommand: UndoableCommand {
|
|||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
for itemSpecifier in itemSpecifiers {
|
for itemSpecifier in itemSpecifiers {
|
||||||
group.enter()
|
group.enter()
|
||||||
itemSpecifier.delete() {
|
itemSpecifier.delete {
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ private struct SidebarItemSpecifier {
|
|||||||
private let folder: Folder?
|
private let folder: Folder?
|
||||||
private let feed: Feed?
|
private let feed: Feed?
|
||||||
private let path: ContainerPath
|
private let path: ContainerPath
|
||||||
private let errorHandler: (Error) -> ()
|
private let errorHandler: (Error) -> Void
|
||||||
|
|
||||||
private var container: Container? {
|
private var container: Container? {
|
||||||
if let parentFolder = parentFolder {
|
if let parentFolder = parentFolder {
|
||||||
@ -113,7 +113,7 @@ private struct SidebarItemSpecifier {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
init?(node: Node, errorHandler: @escaping (Error) -> ()) {
|
init?(node: Node, errorHandler: @escaping (Error) -> Void) {
|
||||||
|
|
||||||
var account: Account?
|
var account: Account?
|
||||||
|
|
||||||
@ -123,13 +123,11 @@ private struct SidebarItemSpecifier {
|
|||||||
self.feed = feed
|
self.feed = feed
|
||||||
self.folder = nil
|
self.folder = nil
|
||||||
account = feed.account
|
account = feed.account
|
||||||
}
|
} else if let folder = node.representedObject as? Folder {
|
||||||
else if let folder = node.representedObject as? Folder {
|
|
||||||
self.feed = nil
|
self.feed = nil
|
||||||
self.folder = folder
|
self.folder = folder
|
||||||
account = folder.account
|
account = folder.account
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if account == nil {
|
if account == nil {
|
||||||
@ -175,8 +173,7 @@ private struct SidebarItemSpecifier {
|
|||||||
|
|
||||||
if let _ = feed {
|
if let _ = feed {
|
||||||
restoreFeed()
|
restoreFeed()
|
||||||
}
|
} else if let _ = folder {
|
||||||
else if let _ = folder {
|
|
||||||
restoreFolder()
|
restoreFolder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,8 +243,7 @@ private extension Node {
|
|||||||
while nomad != nil {
|
while nomad != nil {
|
||||||
if let folder = nomad!.representedObject as? Folder {
|
if let folder = nomad!.representedObject as? Folder {
|
||||||
folders += [folder]
|
folders += [folder]
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
nomad = nomad!.parent
|
nomad = nomad!.parent
|
||||||
@ -274,11 +270,9 @@ private struct DeleteActionName {
|
|||||||
for node in nodes {
|
for node in nodes {
|
||||||
if let _ = node.representedObject as? Feed {
|
if let _ = node.representedObject as? Feed {
|
||||||
numberOfFeeds += 1
|
numberOfFeeds += 1
|
||||||
}
|
} else if let _ = node.representedObject as? Folder {
|
||||||
else if let _ = node.representedObject as? Folder {
|
|
||||||
numberOfFolders += 1
|
numberOfFolders += 1
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return nil // Delete only Feeds and Folders.
|
return nil // Delete only Feeds and Folders.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ final class MarkStatusCommand: UndoableCommand {
|
|||||||
let undoManager: UndoManager
|
let undoManager: UndoManager
|
||||||
let flag: Bool
|
let flag: Bool
|
||||||
let statusKey: ArticleStatus.Key
|
let statusKey: ArticleStatus.Key
|
||||||
var completion: (() -> Void)? = nil
|
var completion: (() -> Void)?
|
||||||
|
|
||||||
init?(initialArticles: [Article], statusKey: ArticleStatus.Key, flag: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
|
init?(initialArticles: [Article], statusKey: ArticleStatus.Key, flag: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ private extension MarkStatusCommand {
|
|||||||
|
|
||||||
static func filteredArticles(_ articles: [Article], _ statusKey: ArticleStatus.Key, _ flag: Bool) -> [Article] {
|
static func filteredArticles(_ articles: [Article], _ statusKey: ArticleStatus.Key, _ flag: Bool) -> [Article] {
|
||||||
|
|
||||||
return articles.filter{ article in
|
return articles.filter { article in
|
||||||
guard article.status.boolStatus(forKey: statusKey) != flag else { return false }
|
guard article.status.boolStatus(forKey: statusKey) != flag else { return false }
|
||||||
guard statusKey == .read else { return true }
|
guard statusKey == .read else { return true }
|
||||||
guard !article.status.read || article.isAvailableToMarkUnread else { return false }
|
guard !article.status.read || article.isAvailableToMarkUnread else { return false }
|
||||||
|
@ -57,7 +57,7 @@ private extension SendToMarsEditCommand {
|
|||||||
let authorName = article.authors?.first?.name
|
let authorName = article.authors?.first?.name
|
||||||
|
|
||||||
let sender = SendToBlogEditorApp(targetDescriptor: targetDescriptor, title: article.title, body: body, summary: article.summary, link: article.externalLink, permalink: article.link, subject: nil, creator: authorName, commentsURL: nil, guid: article.uniqueID, sourceName: article.feed?.nameForDisplay, sourceHomeURL: article.feed?.homePageURL, sourceFeedURL: article.feed?.url)
|
let sender = SendToBlogEditorApp(targetDescriptor: targetDescriptor, title: article.title, body: body, summary: article.summary, link: article.externalLink, permalink: article.link, subject: nil, creator: authorName, commentsURL: nil, guid: article.uniqueID, sourceName: article.feed?.nameForDisplay, sourceHomeURL: article.feed?.homePageURL, sourceFeedURL: article.feed?.url)
|
||||||
let _ = sender.send()
|
sender.send()
|
||||||
}
|
}
|
||||||
|
|
||||||
func appToUse() -> UserApp? {
|
func appToUse() -> UserApp? {
|
||||||
|
@ -116,4 +116,3 @@ struct ArticleStringFormatter {
|
|||||||
return dateFormatter.string(from: date)
|
return dateFormatter.string(from: date)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ func markArticles(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag:
|
|||||||
private func accountAndArticlesDictionary(_ articles: Set<Article>) -> [String: Set<Article>] {
|
private func accountAndArticlesDictionary(_ articles: Set<Article>) -> [String: Set<Article>] {
|
||||||
|
|
||||||
let d = Dictionary(grouping: articles, by: { $0.accountID })
|
let d = Dictionary(grouping: articles, by: { $0.accountID })
|
||||||
return d.mapValues{ Set($0) }
|
return d.mapValues { Set($0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Article {
|
extension Article {
|
||||||
@ -161,24 +161,20 @@ extension Article {
|
|||||||
}
|
}
|
||||||
isFirstAuthor = false
|
isFirstAuthor = false
|
||||||
|
|
||||||
var authorEmailAddress: String? = nil
|
var authorEmailAddress: String?
|
||||||
if let emailAddress = author.emailAddress, !(emailAddress.contains("noreply@") || emailAddress.contains("no-reply@")) {
|
if let emailAddress = author.emailAddress, !(emailAddress.contains("noreply@") || emailAddress.contains("no-reply@")) {
|
||||||
authorEmailAddress = emailAddress
|
authorEmailAddress = emailAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if let emailAddress = authorEmailAddress, emailAddress.contains(" ") {
|
if let emailAddress = authorEmailAddress, emailAddress.contains(" ") {
|
||||||
byline += emailAddress // probably name plus email address
|
byline += emailAddress // probably name plus email address
|
||||||
}
|
} else if let name = author.name, let emailAddress = authorEmailAddress {
|
||||||
else if let name = author.name, let emailAddress = authorEmailAddress {
|
|
||||||
byline += "\(name) <\(emailAddress)>"
|
byline += "\(name) <\(emailAddress)>"
|
||||||
}
|
} else if let name = author.name {
|
||||||
else if let name = author.name {
|
|
||||||
byline += name
|
byline += name
|
||||||
}
|
} else if let emailAddress = authorEmailAddress {
|
||||||
else if let emailAddress = authorEmailAddress {
|
|
||||||
byline += "<\(emailAddress)>"
|
byline += "<\(emailAddress)>"
|
||||||
}
|
} else if let url = author.url {
|
||||||
else if let url = author.url {
|
|
||||||
byline += url
|
byline += url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,7 +195,7 @@ struct ArticlePathKey {
|
|||||||
|
|
||||||
extension Article {
|
extension Article {
|
||||||
|
|
||||||
public var pathUserInfo: [AnyHashable : Any] {
|
public var pathUserInfo: [AnyHashable: Any] {
|
||||||
return [
|
return [
|
||||||
ArticlePathKey.accountID: accountID,
|
ArticlePathKey.accountID: accountID,
|
||||||
ArticlePathKey.accountName: account?.nameForDisplay ?? "",
|
ArticlePathKey.accountName: account?.nameForDisplay ?? "",
|
||||||
|
@ -60,7 +60,7 @@ final class IconImage {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fileprivate enum ImageLuminanceType {
|
private enum ImageLuminanceType {
|
||||||
case regular, bright, dark
|
case regular, bright, dark
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,6 @@ extension CGImage {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum IconSize: Int, CaseIterable {
|
enum IconSize: Int, CaseIterable {
|
||||||
case small = 1
|
case small = 1
|
||||||
case medium = 2
|
case medium = 2
|
||||||
|
@ -40,7 +40,7 @@ extension NSAttributedString {
|
|||||||
let baseDescriptor = baseFont.fontDescriptor
|
let baseDescriptor = baseFont.fontDescriptor
|
||||||
let baseSymbolicTraits = baseDescriptor.symbolicTraits
|
let baseSymbolicTraits = baseDescriptor.symbolicTraits
|
||||||
|
|
||||||
mutable.enumerateAttribute(.font, in: fullRange, options: []) { (font: Any?, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in
|
mutable.enumerateAttribute(.font, in: fullRange, options: []) { (font: Any?, range: NSRange, _: UnsafeMutablePointer<ObjCBool>) in
|
||||||
guard let font = font as? Font else { return }
|
guard let font = font as? Font else { return }
|
||||||
|
|
||||||
let currentDescriptor = font.fontDescriptor
|
let currentDescriptor = font.fontDescriptor
|
||||||
@ -186,20 +186,19 @@ extension NSAttributedString {
|
|||||||
} else {
|
} else {
|
||||||
if char == "&" {
|
if char == "&" {
|
||||||
var entity = "&"
|
var entity = "&"
|
||||||
var lastchar: Character? = nil
|
var lastchar: Character?
|
||||||
|
|
||||||
while let entitychar = iterator.next() {
|
while let entitychar = iterator.next() {
|
||||||
if entitychar.isWhitespace {
|
if entitychar.isWhitespace {
|
||||||
lastchar = entitychar
|
lastchar = entitychar
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.append(entitychar)
|
entity.append(entitychar)
|
||||||
|
|
||||||
if (entitychar == ";") { break }
|
if entitychar == ";" { break }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result.mutableString.append(entity.decodedEntity)
|
result.mutableString.append(entity.decodedEntity)
|
||||||
|
|
||||||
if let lastchar = lastchar { result.mutableString.append(String(lastchar)) }
|
if let lastchar = lastchar { result.mutableString.append(String(lastchar)) }
|
||||||
|
@ -63,5 +63,3 @@ private extension Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@ import AppKit
|
|||||||
import UIKit
|
import UIKit
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import RSCore
|
|
||||||
|
|
||||||
extension RSImage {
|
extension RSImage {
|
||||||
|
|
||||||
static let maxIconSize = 48
|
static let maxIconSize = 48
|
||||||
|
@ -34,7 +34,7 @@ final class FaviconDownloader {
|
|||||||
private var remainingFaviconURLs = [String: ArraySlice<String>]() // homePageURL: array of faviconURLs that haven't been checked yet
|
private var remainingFaviconURLs = [String: ArraySlice<String>]() // homePageURL: array of faviconURLs that haven't been checked yet
|
||||||
private var currentHomePageHasOnlyFaviconICO = false
|
private var currentHomePageHasOnlyFaviconICO = false
|
||||||
|
|
||||||
private var homePageToFaviconURLCache = [String: String]() //homePageURL: faviconURL
|
private var homePageToFaviconURLCache = [String: String]() // homePageURL: faviconURL
|
||||||
private var homePageToFaviconURLCachePath: String
|
private var homePageToFaviconURLCachePath: String
|
||||||
private var homePageToFaviconURLCacheDirty = false {
|
private var homePageToFaviconURLCacheDirty = false {
|
||||||
didSet {
|
didSet {
|
||||||
@ -169,7 +169,7 @@ final class FaviconDownloader {
|
|||||||
self.currentHomePageHasOnlyFaviconICO = faviconURLs.count == 1
|
self.currentHomePageHasOnlyFaviconICO = faviconURLs.count == 1
|
||||||
|
|
||||||
if let firstIconURL = faviconURLs.first {
|
if let firstIconURL = faviconURLs.first {
|
||||||
let _ = self.favicon(with: firstIconURL, homePageURL: url)
|
_ = self.favicon(with: firstIconURL, homePageURL: url)
|
||||||
self.remainingFaviconURLs[url] = faviconURLs.dropFirst()
|
self.remainingFaviconURLs[url] = faviconURLs.dropFirst()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,8 +196,8 @@ final class FaviconDownloader {
|
|||||||
guard let _ = singleFaviconDownloader.iconImage else {
|
guard let _ = singleFaviconDownloader.iconImage else {
|
||||||
if let faviconURLs = remainingFaviconURLs[homePageURL] {
|
if let faviconURLs = remainingFaviconURLs[homePageURL] {
|
||||||
if let nextIconURL = faviconURLs.first {
|
if let nextIconURL = faviconURLs.first {
|
||||||
let _ = favicon(with: nextIconURL, homePageURL: singleFaviconDownloader.homePageURL)
|
_ = favicon(with: nextIconURL, homePageURL: singleFaviconDownloader.homePageURL)
|
||||||
remainingFaviconURLs[homePageURL] = faviconURLs.dropFirst();
|
remainingFaviconURLs[homePageURL] = faviconURLs.dropFirst()
|
||||||
} else {
|
} else {
|
||||||
remainingFaviconURLs[homePageURL] = nil
|
remainingFaviconURLs[homePageURL] = nil
|
||||||
|
|
||||||
|
@ -127,8 +127,7 @@ private extension SingleFaviconDownloader {
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.diskStatus = .onDisk
|
self.diskStatus = .onDisk
|
||||||
}
|
}
|
||||||
}
|
} catch {}
|
||||||
catch {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ final class AuthorAvatarDownloader {
|
|||||||
|
|
||||||
if let imageData = imageDownloader.image(for: avatarURL) {
|
if let imageData = imageDownloader.image(for: avatarURL) {
|
||||||
scaleAndCacheImageData(imageData, avatarURL)
|
scaleAndCacheImageData(imageData, avatarURL)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
waitingForAvatarURLs.insert(avatarURL)
|
waitingForAvatarURLs.insert(avatarURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ extension HTMLMetadata {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var bestImage: HTMLMetadataAppleTouchIcon? = nil
|
var bestImage: HTMLMetadataAppleTouchIcon?
|
||||||
|
|
||||||
for image in icons {
|
for image in icons {
|
||||||
if let size = image.size {
|
if let size = image.size {
|
||||||
@ -31,7 +31,7 @@ extension HTMLMetadata {
|
|||||||
}
|
}
|
||||||
if let size = image.size, let bestImageSize = bestImage!.size {
|
if let size = image.size, let bestImageSize = bestImage!.size {
|
||||||
if size.height > bestImageSize.height && size.width > bestImageSize.width {
|
if size.height > bestImageSize.height && size.width > bestImageSize.width {
|
||||||
bestImage = image;
|
bestImage = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,3 @@ struct ImageUtilities {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,7 @@ struct DefaultFeedsImporter {
|
|||||||
|
|
||||||
static func importDefaultFeeds(account: Account) {
|
static func importDefaultFeeds(account: Account) {
|
||||||
let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")!
|
let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")!
|
||||||
AccountManager.shared.defaultAccount.importOPML(defaultFeedsURL) { result in }
|
AccountManager.shared.defaultAccount.importOPML(defaultFeedsURL) { _ in }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ final class ExtensionContainersFile {
|
|||||||
let errorPointer: NSErrorPointer = nil
|
let errorPointer: NSErrorPointer = nil
|
||||||
let fileCoordinator = NSFileCoordinator()
|
let fileCoordinator = NSFileCoordinator()
|
||||||
let fileURL = URL(fileURLWithPath: ExtensionContainersFile.filePath)
|
let fileURL = URL(fileURLWithPath: ExtensionContainersFile.filePath)
|
||||||
var extensionContainers: ExtensionContainers? = nil
|
var extensionContainers: ExtensionContainers?
|
||||||
|
|
||||||
fileCoordinator.coordinate(readingItemAt: fileURL, options: [], error: errorPointer, byAccessor: { readURL in
|
fileCoordinator.coordinate(readingItemAt: fileURL, options: [], error: errorPointer, byAccessor: { readURL in
|
||||||
if let fileData = try? Data(contentsOf: readURL) {
|
if let fileData = try? Data(contentsOf: readURL) {
|
||||||
|
@ -105,7 +105,7 @@ private extension ExtensionFeedAddRequestFile {
|
|||||||
let fileCoordinator = NSFileCoordinator(filePresenter: self)
|
let fileCoordinator = NSFileCoordinator(filePresenter: self)
|
||||||
let fileURL = URL(fileURLWithPath: ExtensionFeedAddRequestFile.filePath)
|
let fileURL = URL(fileURLWithPath: ExtensionFeedAddRequestFile.filePath)
|
||||||
|
|
||||||
var requests: [ExtensionFeedAddRequest]? = nil
|
var requests: [ExtensionFeedAddRequest]?
|
||||||
|
|
||||||
fileCoordinator.coordinate(writingItemAt: fileURL, options: [.forMerging], error: errorPointer, byAccessor: { url in
|
fileCoordinator.coordinate(writingItemAt: fileURL, options: [.forMerging], error: errorPointer, byAccessor: { url in
|
||||||
do {
|
do {
|
||||||
@ -135,7 +135,7 @@ private extension ExtensionFeedAddRequestFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func processRequest(_ request: ExtensionFeedAddRequest) {
|
func processRequest(_ request: ExtensionFeedAddRequest) {
|
||||||
var destinationAccountID: String? = nil
|
var destinationAccountID: String?
|
||||||
switch request.destinationContainerID {
|
switch request.destinationContainerID {
|
||||||
case .account(let accountID):
|
case .account(let accountID):
|
||||||
destinationAccountID = accountID
|
destinationAccountID = accountID
|
||||||
@ -149,7 +149,7 @@ private extension ExtensionFeedAddRequestFile {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var destinationContainer: Container? = nil
|
var destinationContainer: Container?
|
||||||
if account.containerID == request.destinationContainerID {
|
if account.containerID == request.destinationContainerID {
|
||||||
destinationContainer = account
|
destinationContainer = account
|
||||||
} else {
|
} else {
|
||||||
|
@ -36,4 +36,3 @@ struct SearchFeedDelegate: SmartFeedDelegate {
|
|||||||
// TODO: after 5.0
|
// TODO: after 5.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import Account
|
|||||||
|
|
||||||
final class SmartFeed: PseudoFeed {
|
final class SmartFeed: PseudoFeed {
|
||||||
|
|
||||||
var account: Account? = nil
|
var account: Account?
|
||||||
|
|
||||||
public var defaultReadFilterType: ReadFilterType {
|
public var defaultReadFilterType: ReadFilterType {
|
||||||
return .none
|
return .none
|
||||||
|
@ -32,7 +32,7 @@ extension SmartFeedDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock) {
|
func fetchUnreadArticlesAsync(_ completion: @escaping ArticleSetResultBlock) {
|
||||||
fetchArticlesAsync{ articleSetResult in
|
fetchArticlesAsync { articleSetResult in
|
||||||
switch articleSetResult {
|
switch articleSetResult {
|
||||||
case .success(let articles):
|
case .success(let articles):
|
||||||
completion(.success(articles.unreadArticles()))
|
completion(.success(articles.unreadArticles()))
|
||||||
|
@ -40,4 +40,3 @@ import RSCore
|
|||||||
return plist
|
return plist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,4 +28,3 @@ struct TodayFeedDelegate: SmartFeedDelegate {
|
|||||||
account.fetchUnreadCountForToday(completion)
|
account.fetchUnreadCountForToday(completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import ArticlesDatabase
|
|||||||
|
|
||||||
final class UnreadFeed: PseudoFeed {
|
final class UnreadFeed: PseudoFeed {
|
||||||
|
|
||||||
var account: Account? = nil
|
var account: Account?
|
||||||
|
|
||||||
public var defaultReadFilterType: ReadFilterType {
|
public var defaultReadFilterType: ReadFilterType {
|
||||||
return .alwaysRead
|
return .alwaysRead
|
||||||
|
@ -23,10 +23,10 @@ extension Array where Element == Article {
|
|||||||
func orderedRowIndexes(fromIndex startIndex: Int, wrappingToTop wrapping: Bool) -> [Int] {
|
func orderedRowIndexes(fromIndex startIndex: Int, wrappingToTop wrapping: Bool) -> [Int] {
|
||||||
if startIndex >= self.count {
|
if startIndex >= self.count {
|
||||||
// Wrap around to the top if specified
|
// Wrap around to the top if specified
|
||||||
return wrapping ? Array<Int>(0..<self.count) : []
|
return wrapping ? [Int](0..<self.count) : []
|
||||||
} else {
|
} else {
|
||||||
// Start at the selection and wrap around to the beginning
|
// Start at the selection and wrap around to the beginning
|
||||||
return Array<Int>(startIndex..<self.count) + (wrapping ? Array<Int>(0..<startIndex) : [])
|
return [Int](startIndex..<self.count) + (wrapping ? [Int](0..<startIndex) : [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func rowOfNextUnreadArticle(_ selectedRow: Int, wrappingToTop wrapping: Bool) -> Int? {
|
func rowOfNextUnreadArticle(_ selectedRow: Int, wrappingToTop wrapping: Bool) -> Int? {
|
||||||
@ -45,7 +45,7 @@ extension Array where Element == Article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func articlesForIndexes(_ indexes: IndexSet) -> Set<Article> {
|
func articlesForIndexes(_ indexes: IndexSet) -> Set<Article> {
|
||||||
return Set(indexes.compactMap{ (oneIndex) -> Article? in
|
return Set(indexes.compactMap { (oneIndex) -> Article? in
|
||||||
return articleAtRow(oneIndex)
|
return articleAtRow(oneIndex)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ extension Array where Element == Article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func unreadArticles() -> [Article]? {
|
func unreadArticles() -> [Article]? {
|
||||||
let articles = self.filter{ !$0.status.read }
|
let articles = self.filter { !$0.status.read }
|
||||||
return articles.isEmpty ? nil : articles
|
return articles.isEmpty ? nil : articles
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,4 +130,3 @@ extension Array where Element == Article {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,4 +96,3 @@ final class FetchRequestOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import Foundation
|
|||||||
final class FetchRequestQueue {
|
final class FetchRequestQueue {
|
||||||
|
|
||||||
private var pendingRequests = [FetchRequestOperation]()
|
private var pendingRequests = [FetchRequestOperation]()
|
||||||
private var currentRequest: FetchRequestOperation? = nil
|
private var currentRequest: FetchRequestOperation?
|
||||||
|
|
||||||
var isAnyCurrentRequest: Bool {
|
var isAnyCurrentRequest: Bool {
|
||||||
if let currentRequest = currentRequest {
|
if let currentRequest = currentRequest {
|
||||||
@ -57,6 +57,6 @@ private extension FetchRequestQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeCanceledAndFinishedRequests() {
|
func removeCanceledAndFinishedRequests() {
|
||||||
pendingRequests = pendingRequests.filter{ !$0.isCanceled && !$0.isFinished }
|
pendingRequests = pendingRequests.filter { !$0.isCanceled && !$0.isFinished }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,4 +30,3 @@ struct LatestArticle: Codable, Identifiable {
|
|||||||
let pubDate: String
|
let pubDate: String
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import RSCore
|
|||||||
import Articles
|
import Articles
|
||||||
import Account
|
import Account
|
||||||
|
|
||||||
|
|
||||||
public final class WidgetDataEncoder {
|
public final class WidgetDataEncoder {
|
||||||
|
|
||||||
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application")
|
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application")
|
||||||
@ -40,7 +39,7 @@ public final class WidgetDataEncoder {
|
|||||||
os_log(.debug, log: log, "Starting encoding widget data.")
|
os_log(.debug, log: log, "Starting encoding widget data.")
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.encodeWidgetData() { latestData in
|
self.encodeWidgetData { latestData in
|
||||||
guard let latestData = latestData else {
|
guard let latestData = latestData else {
|
||||||
self.isRunning = false
|
self.isRunning = false
|
||||||
return
|
return
|
||||||
@ -67,7 +66,7 @@ public final class WidgetDataEncoder {
|
|||||||
|
|
||||||
private func encodeWidgetData(completion: @escaping (WidgetData?) -> Void) {
|
private func encodeWidgetData(completion: @escaping (WidgetData?) -> Void) {
|
||||||
let dispatchGroup = DispatchGroup()
|
let dispatchGroup = DispatchGroup()
|
||||||
var groupError: Error? = nil
|
var groupError: Error?
|
||||||
|
|
||||||
var unread = [LatestArticle]()
|
var unread = [LatestArticle]()
|
||||||
|
|
||||||
@ -142,7 +141,7 @@ public final class WidgetDataEncoder {
|
|||||||
currentStarredCount: (try? AccountManager.shared.fetchCountForStarredArticles()) ?? 0,
|
currentStarredCount: (try? AccountManager.shared.fetchCountForStarredArticles()) ?? 0,
|
||||||
unreadArticles: unread,
|
unreadArticles: unread,
|
||||||
starredArticles: starred,
|
starredArticles: starred,
|
||||||
todayArticles:today,
|
todayArticles: today,
|
||||||
lastUpdateTime: Date())
|
lastUpdateTime: Date())
|
||||||
completion(latestData)
|
completion(latestData)
|
||||||
}
|
}
|
||||||
@ -178,5 +177,3 @@ public final class WidgetDataEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user