Implement Timeline read filter
This commit is contained in:
parent
e24716c944
commit
6c236fc0e3
|
@ -33,7 +33,7 @@ struct SidebarView: View {
|
||||||
AppAssets.filterInactiveImage
|
AppAssets.filterInactiveImage
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.padding(.top).padding(.trailing)
|
.padding(.top, 8).padding(.trailing)
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
ZStack {
|
ZStack {
|
||||||
|
|
|
@ -23,7 +23,7 @@ struct TimelineContainerView: View {
|
||||||
.environmentObject(sceneModel.timelineModel)
|
.environmentObject(sceneModel.timelineModel)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
sceneModel.timelineModel.undoManager = undoManager
|
sceneModel.timelineModel.undoManager = undoManager
|
||||||
sceneModel.timelineModel.rebuildTimelineItems(feeds: feeds)
|
sceneModel.timelineModel.fetchArticles(feeds: feeds)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
|
|
|
@ -22,8 +22,8 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||||
|
|
||||||
@Published var nameForDisplay = ""
|
@Published var nameForDisplay = ""
|
||||||
@Published var timelineItems = [TimelineItem]()
|
@Published var timelineItems = [TimelineItem]()
|
||||||
@Published var selectedArticleIDs = Set<String>()
|
@Published var selectedArticleIDs = Set<String>() // Don't use directly. Use selectedArticles
|
||||||
@Published var selectedArticleID: String? = .none
|
@Published var selectedArticleID: String? = .none // Don't use directly. Use selectedArticles
|
||||||
@Published var selectedArticles = [Article]()
|
@Published var selectedArticles = [Article]()
|
||||||
@Published var isReadFiltered = false
|
@Published var isReadFiltered = false
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||||
private var selectedArticleIDsCancellable: AnyCancellable?
|
private var selectedArticleIDsCancellable: AnyCancellable?
|
||||||
private var selectedArticleIDCancellable: AnyCancellable?
|
private var selectedArticleIDCancellable: AnyCancellable?
|
||||||
private var selectedArticlesCancellable: AnyCancellable?
|
private var selectedArticlesCancellable: AnyCancellable?
|
||||||
|
private var selectedReadFilteredCancellable: AnyCancellable?
|
||||||
|
|
||||||
private var fetchSerialNumber = 0
|
private var fetchSerialNumber = 0
|
||||||
private let fetchRequestQueue = FetchRequestQueue()
|
private let fetchRequestQueue = FetchRequestQueue()
|
||||||
|
@ -95,11 +96,16 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedReadFilteredCancellable = $isReadFiltered.sink { [weak self] filter in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.rebuildTimelineItems(isReadFiltered: filter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: API
|
// MARK: API
|
||||||
|
|
||||||
func rebuildTimelineItems(feeds: [Feed]) {
|
func fetchArticles(feeds: [Feed]) {
|
||||||
if feeds.count == 1 {
|
if feeds.count == 1 {
|
||||||
nameForDisplay = feeds.first!.nameForDisplay
|
nameForDisplay = feeds.first!.nameForDisplay
|
||||||
} else {
|
} else {
|
||||||
|
@ -259,8 +265,20 @@ private extension TimelineModel {
|
||||||
|
|
||||||
func replaceArticles(with unsortedArticles: Set<Article>) {
|
func replaceArticles(with unsortedArticles: Set<Article>) {
|
||||||
articles = Array(unsortedArticles).sortedByDate(sortDirection ? .orderedDescending : .orderedAscending, groupByFeed: groupByFeed)
|
articles = Array(unsortedArticles).sortedByDate(sortDirection ? .orderedDescending : .orderedAscending, groupByFeed: groupByFeed)
|
||||||
timelineItems = articles.map { TimelineItem(article: $0) }
|
rebuildTimelineItems(isReadFiltered: isReadFiltered)
|
||||||
// TODO: Update unread counts and other item done in didSet on AppKit
|
// TODO: Update unread counts and other item done in didSet on AppKit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rebuildTimelineItems(isReadFiltered: Bool) {
|
||||||
|
let selectedArticleIDs = selectedArticles.map { $0.articleID }
|
||||||
|
|
||||||
|
timelineItems = articles.compactMap { article in
|
||||||
|
if isReadFiltered && article.status.read && !selectedArticleIDs.contains(article.articleID) {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return TimelineItem(article: article)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,34 @@ struct TimelineView: View {
|
||||||
|
|
||||||
@ViewBuilder var body: some View {
|
@ViewBuilder var body: some View {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
ZStack {
|
VStack {
|
||||||
NavigationLink(destination: ArticleContainerView(articles: timelineModel.selectedArticles), isActive: $navigate) {
|
HStack {
|
||||||
EmptyView()
|
Spacer()
|
||||||
}.hidden()
|
Button (action: {
|
||||||
List(timelineModel.timelineItems, selection: $timelineModel.selectedArticleIDs) { timelineItem in
|
withAnimation {
|
||||||
TimelineItemView(timelineItem: timelineItem)
|
timelineModel.isReadFiltered.toggle()
|
||||||
|
}
|
||||||
|
}, label: {
|
||||||
|
if timelineModel.isReadFiltered {
|
||||||
|
AppAssets.filterActiveImage
|
||||||
|
} else {
|
||||||
|
AppAssets.filterInactiveImage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.padding(.top, 8).padding(.trailing)
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
}
|
||||||
|
ZStack {
|
||||||
|
NavigationLink(destination: ArticleContainerView(articles: timelineModel.selectedArticles), isActive: $navigate) {
|
||||||
|
EmptyView()
|
||||||
|
}.hidden()
|
||||||
|
List(timelineModel.timelineItems, selection: $timelineModel.selectedArticleIDs) { timelineItem in
|
||||||
|
TimelineItemView(timelineItem: timelineItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChange(of: timelineModel.selectedArticleIDs) { value in
|
||||||
|
navigate = !timelineModel.selectedArticleIDs.isEmpty
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.onChange(of: timelineModel.selectedArticleIDs) { value in
|
|
||||||
navigate = !timelineModel.selectedArticleIDs.isEmpty
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
List(timelineModel.timelineItems) { timelineItem in
|
List(timelineModel.timelineItems) { timelineItem in
|
||||||
|
|
Loading…
Reference in New Issue