Added ability to group sorted articles by feed
This commit is contained in:
parent
1718810701
commit
00e009a82c
|
@ -340,6 +340,8 @@
|
|||
D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; };
|
||||
DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82AB09231003F6002269DF /* SharingTests.swift */; };
|
||||
DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF999FF622B5AEFA0064B687 /* SafariView.swift */; };
|
||||
FF3ABF13232599810074C542 /* ArticleArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF09232599450074C542 /* ArticleArrayTests.swift */; };
|
||||
FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -975,6 +977,8 @@
|
|||
D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = "<group>"; };
|
||||
DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = "<group>"; };
|
||||
DF999FF622B5AEFA0064B687 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
|
||||
FF3ABF09232599450074C542 /* ArticleArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleArrayTests.swift; sourceTree = "<group>"; };
|
||||
FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorter.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -1254,8 +1258,9 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
84F204DF1FAACBB30076E152 /* ArticleArray.swift */,
|
||||
84CAFCA322BC8C08007694F0 /* FetchRequestQueue.swift */,
|
||||
FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */,
|
||||
84CAFCAE22BC8C35007694F0 /* FetchRequestOperation.swift */,
|
||||
84CAFCA322BC8C08007694F0 /* FetchRequestQueue.swift */,
|
||||
849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */,
|
||||
);
|
||||
path = Timeline;
|
||||
|
@ -1877,6 +1882,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
84F9EAD0213660A100CF2DE4 /* ScriptingTests */,
|
||||
FF3ABF09232599450074C542 /* ArticleArrayTests.swift */,
|
||||
84F9EAE3213660A100CF2DE4 /* NetNewsWireTests.swift */,
|
||||
DD82AB09231003F6002269DF /* SharingTests.swift */,
|
||||
84F9EAE4213660A100CF2DE4 /* Info.plist */,
|
||||
|
@ -2608,6 +2614,7 @@
|
|||
849A978A1ED9ECEF007D329B /* ArticleStylesManager.swift in Sources */,
|
||||
8405DD8A2213E0E3008CE1BF /* DetailContainerView.swift in Sources */,
|
||||
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */,
|
||||
FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */,
|
||||
84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */,
|
||||
849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */,
|
||||
84E185C3203BB12600F69BFA /* MultilineTextFieldSizer.swift in Sources */,
|
||||
|
@ -2686,6 +2693,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FF3ABF13232599810074C542 /* ArticleArrayTests.swift in Sources */,
|
||||
DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */,
|
||||
84F9EAEB213660A100CF2DE4 /* testIterativeCreateAndDeleteFeed.applescript in Sources */,
|
||||
84F9EAF4213660A100CF2DE4 /* testGenericScript.applescript in Sources */,
|
||||
|
|
|
@ -90,3 +90,21 @@ extension Article {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: SortableArticle
|
||||
|
||||
extension Article: SortableArticle {
|
||||
|
||||
var sortableName: String {
|
||||
return feed?.name ?? ""
|
||||
}
|
||||
|
||||
var sortableDate: Date {
|
||||
return logicalDatePublished
|
||||
}
|
||||
|
||||
var sortableID: String {
|
||||
return articleID
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,22 +49,11 @@ extension Array where Element == Article {
|
|||
return articleAtRow(oneIndex)
|
||||
})
|
||||
}
|
||||
|
||||
func sortedByDate(_ sortDirection: ComparisonResult) -> ArticleArray {
|
||||
|
||||
let articles = sorted { (article1, article2) -> Bool in
|
||||
if article1.logicalDatePublished == article2.logicalDatePublished {
|
||||
return article1.articleID < article2.articleID
|
||||
}
|
||||
if sortDirection == .orderedDescending {
|
||||
return article1.logicalDatePublished > article2.logicalDatePublished
|
||||
}
|
||||
return article1.logicalDatePublished < article2.logicalDatePublished
|
||||
}
|
||||
|
||||
return articles
|
||||
func sortedByDate(_ sortDirection: ComparisonResult, groupByFeed: Bool = false) -> ArticleArray {
|
||||
return ArticleSorter.sortedByDate(articles: self, sortDirection: sortDirection, groupByFeed: groupByFeed)
|
||||
}
|
||||
|
||||
|
||||
func canMarkAllAsRead() -> Bool {
|
||||
|
||||
return anyArticleIsUnread()
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// ArticleSorter.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Phil Viso on 9/8/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Articles
|
||||
import Foundation
|
||||
|
||||
protocol SortableArticle {
|
||||
var sortableName: String { get }
|
||||
var sortableDate: Date { get }
|
||||
var sortableID: String { get }
|
||||
}
|
||||
|
||||
struct ArticleSorter {
|
||||
|
||||
static func sortedByDate<T: SortableArticle>(articles: [T],
|
||||
sortDirection: ComparisonResult,
|
||||
groupByFeed: Bool) -> [T] {
|
||||
let articles = articles.sorted { (article1, article2) -> Bool in
|
||||
if groupByFeed {
|
||||
let feedName1 = article1.sortableName
|
||||
let feedName2 = article2.sortableName
|
||||
|
||||
let comparison = feedName1.caseInsensitiveCompare(feedName2)
|
||||
switch comparison {
|
||||
case .orderedSame:
|
||||
return isSortedByDate(article1, article2, sortDirection: sortDirection)
|
||||
case .orderedAscending, .orderedDescending:
|
||||
return comparison == .orderedAscending
|
||||
}
|
||||
} else {
|
||||
return isSortedByDate(article1, article2, sortDirection: sortDirection)
|
||||
}
|
||||
}
|
||||
|
||||
return articles
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private static func isSortedByDate(_ lhs: SortableArticle,
|
||||
_ rhs: SortableArticle,
|
||||
sortDirection: ComparisonResult) -> Bool {
|
||||
if lhs.sortableDate == rhs.sortableDate {
|
||||
return lhs.sortableID < rhs.sortableID
|
||||
}
|
||||
if sortDirection == .orderedDescending {
|
||||
return lhs.sortableDate > rhs.sortableDate
|
||||
}
|
||||
return lhs.sortableDate < rhs.sortableDate
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// ArticleArrayTests.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Phil Viso on 9/8/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Articles
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
@testable import NetNewsWire
|
||||
|
||||
class ArticleArrayTests: XCTestCase {
|
||||
|
||||
func testSortByDateAscending() {
|
||||
let now = Date()
|
||||
|
||||
// Test data includes a mixture of articles in the past and future, as well as articles with the same date
|
||||
let article1 = TestArticle(sortableName: "Phil's Feed", sortableDate: now, sortableID: "456")
|
||||
let article2 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "789")
|
||||
let article3 = TestArticle(sortableName: "Sally's Feed", sortableDate: now, sortableID: "123")
|
||||
let article4 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "345")
|
||||
let article5 = TestArticle(sortableName: "Paul's Feed", sortableDate: Date(timeInterval: -120.0, since: now), sortableID: "567")
|
||||
let article6 = TestArticle(sortableName: "phil's Feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "567")
|
||||
|
||||
let articles = [article1, article2, article3, article4, article5, article6]
|
||||
let sortedArticles = ArticleSorter.sortedByDate(articles: articles,
|
||||
sortDirection: .orderedAscending,
|
||||
groupByFeed: false)
|
||||
XCTAssertEqual(sortedArticles, [article5, article4, article3, article1, article2, article6])
|
||||
}
|
||||
|
||||
func testSortByDateAscendingWithGroupByFeed() {
|
||||
let now = Date()
|
||||
|
||||
// Test data includes multiple groups (with case-insentive names), articles in the past and future,
|
||||
// as well as articles with the same date
|
||||
let article1 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -240.0, since: now), sortableID: "123")
|
||||
let article2 = TestArticle(sortableName: "Phil's Feed", sortableDate: now, sortableID: "456")
|
||||
let article3 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "234")
|
||||
let article4 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -120.0, since: now), sortableID: "123")
|
||||
let article5 = TestArticle(sortableName: "phil's feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "456")
|
||||
let article6 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "123")
|
||||
let article7 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "123")
|
||||
let article8 = TestArticle(sortableName: "phil's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "456")
|
||||
let article9 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "345")
|
||||
let article10 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -15.0, since: now), sortableID: "123")
|
||||
let article11 = TestArticle(sortableName: "Matt's Feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "123")
|
||||
let article12 = TestArticle(sortableName: "Claire's Feed", sortableDate: now, sortableID: "123")
|
||||
|
||||
let articles = [article1, article2, article3, article4, article5, article6, article7, article8, article9, article10, article11, article12]
|
||||
let sortedArticles = ArticleSorter.sortedByDate(articles: articles,
|
||||
sortDirection: .orderedAscending,
|
||||
groupByFeed: true)
|
||||
XCTAssertEqual(sortedArticles, [article12, article6, article3, article9, article11, article8, article2, article5, article1, article4, article7, article10])
|
||||
}
|
||||
|
||||
func testSortByDateDescending() {
|
||||
let now = Date()
|
||||
|
||||
// Test data includes a mixture of articles in the past and future, as well as articles with the same date
|
||||
let article1 = TestArticle(sortableName: "Phil's Feed", sortableDate: now, sortableID: "456")
|
||||
let article2 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "789")
|
||||
let article3 = TestArticle(sortableName: "Sally's Feed", sortableDate: now, sortableID: "123")
|
||||
let article4 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "345")
|
||||
let article5 = TestArticle(sortableName: "Paul's Feed", sortableDate: Date(timeInterval: -120.0, since: now), sortableID: "567")
|
||||
let article6 = TestArticle(sortableName: "phil's Feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "567")
|
||||
|
||||
let articles = [article1, article2, article3, article4, article5, article6]
|
||||
let sortedArticles = ArticleSorter.sortedByDate(articles: articles,
|
||||
sortDirection: .orderedDescending,
|
||||
groupByFeed: false)
|
||||
XCTAssertEqual(sortedArticles, [article6, article3, article1, article2, article4, article5])
|
||||
}
|
||||
|
||||
func testSortByDateDescendingWithGroupByFeed() {
|
||||
let now = Date()
|
||||
|
||||
// Test data includes multiple groups (with case-insentive names), articles in the past and future,
|
||||
// as well as articles with the same date
|
||||
let article1 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -240.0, since: now), sortableID: "123")
|
||||
let article2 = TestArticle(sortableName: "Phil's Feed", sortableDate: now, sortableID: "456")
|
||||
let article3 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "234")
|
||||
let article4 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -120.0, since: now), sortableID: "123")
|
||||
let article5 = TestArticle(sortableName: "phil's feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "456")
|
||||
let article6 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "123")
|
||||
let article7 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "123")
|
||||
let article8 = TestArticle(sortableName: "phil's Feed", sortableDate: Date(timeInterval: -60.0, since: now), sortableID: "456")
|
||||
let article9 = TestArticle(sortableName: "Matt's Feed", sortableDate: now, sortableID: "345")
|
||||
let article10 = TestArticle(sortableName: "Susie's Feed", sortableDate: Date(timeInterval: -15.0, since: now), sortableID: "123")
|
||||
let article11 = TestArticle(sortableName: "Matt's Feed", sortableDate: Date(timeInterval: 60.0, since: now), sortableID: "123")
|
||||
let article12 = TestArticle(sortableName: "Claire's Feed", sortableDate: now, sortableID: "123")
|
||||
|
||||
let articles = [article1, article2, article3, article4, article5, article6, article7, article8, article9, article10, article11, article12]
|
||||
let sortedArticles = ArticleSorter.sortedByDate(articles: articles,
|
||||
sortDirection: .orderedDescending,
|
||||
groupByFeed: true)
|
||||
XCTAssertEqual(sortedArticles, [article12, article11, article6, article3, article9, article5, article2, article8, article10, article7, article4, article1])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private struct TestArticle: SortableArticle, Equatable {
|
||||
let sortableName: String
|
||||
let sortableDate: Date
|
||||
let sortableID: String
|
||||
}
|
Loading…
Reference in New Issue