2017-11-02 04:45:38 +01:00
|
|
|
//
|
|
|
|
// ArticleArray.swift
|
2018-08-29 07:18:24 +02:00
|
|
|
// NetNewsWire
|
2017-11-02 04:45:38 +01:00
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 11/1/17.
|
|
|
|
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
2018-07-24 03:29:08 +02:00
|
|
|
import Articles
|
2017-11-02 04:45:38 +01:00
|
|
|
|
2017-11-02 06:40:28 +01:00
|
|
|
typealias ArticleArray = [Article]
|
|
|
|
|
2017-11-02 04:45:38 +01:00
|
|
|
extension Array where Element == Article {
|
|
|
|
|
|
|
|
func articleAtRow(_ row: Int) -> Article? {
|
|
|
|
if row < 0 || row == NSNotFound || row > count - 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return self[row]
|
|
|
|
}
|
|
|
|
|
2020-11-01 23:33:48 +01:00
|
|
|
func orderedRowIndexes(fromIndex startIndex: Int, wrappingToTop wrapping: Bool) -> [Int] {
|
|
|
|
if startIndex >= self.count {
|
|
|
|
// Wrap around to the top if specified
|
|
|
|
return wrapping ? Array<Int>(0..<self.count) : []
|
|
|
|
} else {
|
|
|
|
// Start at the selection and wrap around to the beginning
|
|
|
|
return Array<Int>(startIndex..<self.count) + (wrapping ? Array<Int>(0..<startIndex) : [])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func rowOfNextUnreadArticle(_ selectedRow: Int, wrappingToTop wrapping: Bool) -> Int? {
|
2017-11-02 06:40:28 +01:00
|
|
|
if isEmpty {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-01 23:33:48 +01:00
|
|
|
for rowIndex in orderedRowIndexes(fromIndex: selectedRow + 1, wrappingToTop: wrapping) {
|
2017-11-02 06:40:28 +01:00
|
|
|
let article = articleAtRow(rowIndex)!
|
|
|
|
if !article.status.read {
|
|
|
|
return rowIndex
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func articlesForIndexes(_ indexes: IndexSet) -> Set<Article> {
|
2018-01-28 03:50:48 +01:00
|
|
|
return Set(indexes.compactMap{ (oneIndex) -> Article? in
|
2017-11-02 06:40:28 +01:00
|
|
|
return articleAtRow(oneIndex)
|
|
|
|
})
|
|
|
|
}
|
2018-01-28 20:33:04 +01:00
|
|
|
|
2019-09-08 23:48:50 +02:00
|
|
|
func sortedByDate(_ sortDirection: ComparisonResult, groupByFeed: Bool = false) -> ArticleArray {
|
|
|
|
return ArticleSorter.sortedByDate(articles: self, sortDirection: sortDirection, groupByFeed: groupByFeed)
|
2017-11-02 06:40:28 +01:00
|
|
|
}
|
2019-09-08 23:48:50 +02:00
|
|
|
|
2017-11-02 06:40:28 +01:00
|
|
|
func canMarkAllAsRead() -> Bool {
|
2018-02-10 08:16:12 +01:00
|
|
|
return anyArticleIsUnread()
|
|
|
|
}
|
|
|
|
|
|
|
|
func anyArticlePassesTest(_ test: ((Article) -> Bool)) -> Bool {
|
2017-11-02 06:40:28 +01:00
|
|
|
for article in self {
|
2018-02-10 08:16:12 +01:00
|
|
|
if test(article) {
|
2017-11-02 06:40:28 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2018-02-10 08:16:12 +01:00
|
|
|
|
2020-02-29 19:30:35 +01:00
|
|
|
func anyArticleIsReadAndCanMarkUnread() -> Bool {
|
|
|
|
return anyArticlePassesTest { $0.status.read && $0.isAvailableToMarkUnread }
|
2018-02-10 08:16:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func anyArticleIsUnread() -> Bool {
|
|
|
|
return anyArticlePassesTest { !$0.status.read }
|
|
|
|
}
|
|
|
|
|
|
|
|
func anyArticleIsStarred() -> Bool {
|
|
|
|
return anyArticlePassesTest { $0.status.starred }
|
|
|
|
}
|
|
|
|
|
|
|
|
func anyArticleIsUnstarred() -> Bool {
|
|
|
|
return anyArticlePassesTest { !$0.status.starred }
|
|
|
|
}
|
2018-02-19 06:49:46 +01:00
|
|
|
|
|
|
|
func unreadArticles() -> [Article]? {
|
|
|
|
let articles = self.filter{ !$0.status.read }
|
|
|
|
return articles.isEmpty ? nil : articles
|
|
|
|
}
|
2019-02-09 04:53:41 +01:00
|
|
|
|
|
|
|
func representSameArticlesInSameOrder(as otherArticles: [Article]) -> Bool {
|
|
|
|
if self.count != otherArticles.count {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
var i = 0
|
|
|
|
for article in self {
|
|
|
|
let otherArticle = otherArticles[i]
|
|
|
|
if article.account != otherArticle.account || article.articleID != otherArticle.articleID {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2020-01-07 21:54:21 +01:00
|
|
|
|
|
|
|
func articlesAbove(article: Article) -> [Article] {
|
2020-07-20 23:21:48 +02:00
|
|
|
guard let position = firstIndex(of: article) else { return [] }
|
|
|
|
return articlesAbove(position: position)
|
|
|
|
}
|
|
|
|
|
|
|
|
func articlesAbove(position: Int) -> [Article] {
|
|
|
|
guard position < count else { return [] }
|
2020-01-07 21:54:21 +01:00
|
|
|
let articlesAbove = self[..<position]
|
|
|
|
return Array(articlesAbove)
|
|
|
|
}
|
|
|
|
|
|
|
|
func articlesBelow(article: Article) -> [Article] {
|
2020-07-20 23:21:48 +02:00
|
|
|
guard let position = firstIndex(of: article) else { return [] }
|
|
|
|
return articlesBelow(position: position)
|
|
|
|
}
|
|
|
|
|
|
|
|
func articlesBelow(position: Int) -> [Article] {
|
|
|
|
guard position < count else { return [] }
|
2020-01-07 21:54:21 +01:00
|
|
|
var articlesBelow = Array(self[position...])
|
|
|
|
guard !articlesBelow.isEmpty else {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
articlesBelow.removeFirst()
|
|
|
|
return articlesBelow
|
|
|
|
}
|
2020-07-20 23:21:48 +02:00
|
|
|
|
2017-11-02 06:40:28 +01:00
|
|
|
}
|
|
|
|
|