Improved loading of feature filters

This commit is contained in:
Jackson Harper
2023-12-15 19:35:57 +08:00
parent f392c022a4
commit 59d68b7cf2
7 changed files with 62 additions and 137 deletions

View File

@ -39,7 +39,7 @@ struct LibraryFeatureCardNavigationLink: View {
}
)
.confirmationDialog("", isPresented: $showFeatureActions) {
if FeaturedItemFilter(rawValue: viewModel.featureFilter) == .pinned {
if FeaturedItemFilter(rawValue: viewModel.fetcher.featureFilter) == .pinned {
Button("Unpin", action: {
viewModel.unpinItem(dataService: dataService, item: item)
})
@ -53,7 +53,7 @@ struct LibraryFeatureCardNavigationLink: View {
Button("Remove", action: {
viewModel.removeLibraryItem(dataService: dataService, objectID: item.objectID)
})
if FeaturedItemFilter(rawValue: viewModel.featureFilter) != .pinned {
if FeaturedItemFilter(rawValue: viewModel.fetcher.featureFilter) != .pinned {
Button("Mark Read", action: {
viewModel.markRead(dataService: dataService, item: item)
})

View File

@ -9,13 +9,13 @@ import Utils
import Views
@MainActor final class LibraryItemFetcher: NSObject, ObservableObject {
let folder = "inbox"
@Published var items = [Models.LibraryItem]()
var itemsPublisher: Published<[Models.LibraryItem]>.Publisher { $items }
@Published var featureItems = [Models.LibraryItem]()
private var fetchedResultsController: NSFetchedResultsController<Models.LibraryItem>?
@AppStorage(UserDefaultKey.lastSelectedFeaturedItemFilter.rawValue) var featureFilter = FeaturedItemFilter.continueReading.rawValue
var cursor: String?
// These are used to make sure we handle search result
@ -23,8 +23,11 @@ import Views
var searchIdx = 0
var receivedIdx = 0
func setItems(_: NSManagedObjectContext, _ items: [Models.LibraryItem]) {
func setItems(_ context: NSManagedObjectContext, _ items: [Models.LibraryItem]) {
self.items = items
if let filter = FeaturedItemFilter(rawValue: featureFilter) {
updateFeatureFilter(context: context, filter: filter)
}
}
func loadCurrentViewer(dataService: DataService) async {
@ -226,6 +229,29 @@ import Views
return query
}
func refreshFeatureItems(dataService: DataService) {
if let featureFilter = FeaturedItemFilter(rawValue: self.featureFilter) {
updateFeatureFilter(context: dataService.viewContext, filter: featureFilter)
}
}
func updateFeatureFilter(context: NSManagedObjectContext, filter: FeaturedItemFilter?) {
if let filter = filter {
Task {
featureFilter = filter.rawValue
featureItems = await loadFeatureItems(
context: context,
predicate: filter.predicate,
sort: filter.sortDescriptor
)
print("FEATURE ITEMS: ", featureItems)
}
} else {
featureItems = []
}
}
}
extension LibraryItemFetcher: NSFetchedResultsControllerDelegate {

View File

@ -131,15 +131,9 @@ struct AnimatingCellHeight: AnimatableModifier {
.fullScreenCover(isPresented: $showExpandedAudioPlayer) {
ExpandedAudioPlayer()
}
.sheet(isPresented: $showOpenAIVoices) {
OpenAIVoicesModal(audioController: audioController)
}
.onAppear {
if !openAIPrimerDisplayed, !Voices.isOpenAIVoice(self.audioController.currentVoice) {
showOpenAIVoices = true
openAIPrimerDisplayed = true
}
}
// .onAppear {
// viewModel.refreshFeatureItems(dataService: dataService)
// }
.toolbar {
toolbarItems
}
@ -182,6 +176,9 @@ struct AnimatingCellHeight: AnimatableModifier {
LibraryAddLinkView()
}
}
.introspectNavigationController { nav in
nav.delegate = viewModel
}
.task {
await viewModel.loadFilters(dataService: dataService)
}
@ -469,17 +466,17 @@ struct AnimatingCellHeight: AnimatableModifier {
HStack {
Menu(content: {
Button(action: {
viewModel.updateFeatureFilter(context: dataService.viewContext, filter: .continueReading)
viewModel.fetcher.updateFeatureFilter(context: dataService.viewContext, filter: .continueReading)
}, label: {
Text("Continue Reading")
})
Button(action: {
viewModel.updateFeatureFilter(context: dataService.viewContext, filter: .pinned)
viewModel.fetcher.updateFeatureFilter(context: dataService.viewContext, filter: .pinned)
}, label: {
Text("Pinned")
})
Button(action: {
viewModel.updateFeatureFilter(context: dataService.viewContext, filter: .newsletters)
viewModel.fetcher.updateFeatureFilter(context: dataService.viewContext, filter: .newsletters)
}, label: {
Text("Newsletters")
})
@ -493,7 +490,7 @@ struct AnimatingCellHeight: AnimatableModifier {
HStack(alignment: .center) {
Image(systemName: "line.3.horizontal.decrease")
.font(Font.system(size: 13, weight: .regular))
Text((FeaturedItemFilter(rawValue: viewModel.featureFilter) ?? .continueReading).title)
Text((FeaturedItemFilter(rawValue: viewModel.fetcher.featureFilter) ?? .continueReading).title)
.font(Font.system(size: 13, weight: .medium))
}
.tint(Color(hex: "#007AFF"))
@ -510,17 +507,17 @@ struct AnimatingCellHeight: AnimatableModifier {
GeometryReader { geo in
ScrollView(.horizontal, showsIndicators: false) {
if viewModel.featureItems.count > 0 {
if viewModel.fetcher.featureItems.count > 0 {
HStack(alignment: .top, spacing: 15) {
Spacer(minLength: 1).frame(width: 1)
ForEach(viewModel.featureItems) { item in
ForEach(viewModel.fetcher.featureItems) { item in
LibraryFeatureCardNavigationLink(item: item, viewModel: viewModel)
}
Spacer(minLength: 1).frame(width: 1)
}
.padding(.top, 0)
} else {
Text((FeaturedItemFilter(rawValue: viewModel.featureFilter) ?? .continueReading).emptyMessage)
Text((FeaturedItemFilter(rawValue: viewModel.fetcher.featureFilter) ?? .continueReading).emptyMessage)
.padding(.horizontal, UIDevice.isIPad ? 20 : 10)
.font(Font.system(size: 14, weight: .regular))
.foregroundColor(Color(hex: "#898989"))
@ -1034,10 +1031,10 @@ struct LinkDestination: View {
func fakeLibraryItems(dataService _: DataService) -> [LibraryItemData] {
Array(
repeatElement(UUID().uuidString, count: 20)
.map { uuid in
repeatElement(0, count: 20)
.map { _ in
LibraryItemData(
id: uuid,
id: UUID().uuidString,
title: "fake title that is kind of long so it looks better",
pageURLString: "",
isArchived: false,

View File

@ -5,7 +5,7 @@ import SwiftUI
import Utils
import Views
@MainActor final class HomeFeedViewModel: NSObject, ObservableObject, NSFetchedResultsControllerDelegate {
@MainActor final class HomeFeedViewModel: NSObject, ObservableObject, UINavigationControllerDelegate {
let folder: String
let fetcher: LibraryItemFetcher
let listConfig: LibraryListConfig
@ -21,15 +21,10 @@ import Views
@Published var presentWebContainer = false
@Published var showLoadingBar = true
@Published var selectedLinkItem: NSManagedObjectID? // used by mac app only
@Published var selectedItem: Models.LibraryItem?
@Published var linkIsActive = false
@Published var showLabelsSheet = false
@Published var showFiltersModal = false
@Published var showCommunityModal = false
@Published var featureItems = [Models.LibraryItem]()
@Published var showSnackbar = false
@Published var snackbarOperation: SnackbarOperation?
@ -41,8 +36,6 @@ import Views
@Published var appliedSort = LinkedItemSort.newest.rawValue
@AppStorage(UserDefaultKey.hideFeatureSection.rawValue) var hideFeatureSection = false
@AppStorage(UserDefaultKey.lastSelectedFeaturedItemFilter.rawValue) var featureFilter = FeaturedItemFilter.continueReading.rawValue
@AppStorage("LibraryTabView::hideFollowingTab") var hideFollowingTab = false
@Published var appliedFilter: InternalFilter? {
@ -63,22 +56,6 @@ import Views
super.init()
}
func updateFeatureFilter(context: NSManagedObjectContext, filter: FeaturedItemFilter?) {
if let filter = filter {
Task {
featureFilter = filter.rawValue
featureItems = await loadFeatureItems(
context: context,
predicate: filter.predicate,
sort: filter.sortDescriptor
)
}
} else {
featureItems = []
}
}
func loadFilters(dataService: DataService) async {
switch folder {
case "following":
@ -156,7 +133,6 @@ import Views
showLoadingBar = isRefresh
await fetcher.loadItems(dataService: dataService, filterState: filterState, isRefresh: isRefresh)
updateFeatureFilter(context: dataService.viewContext, filter: FeaturedItemFilter(rawValue: featureFilter))
isLoading = false
showLoadingBar = false
@ -176,7 +152,16 @@ import Views
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [sort]
return (try? context.fetch(fetchRequest)) ?? []
print("using predicate to load feature items: ", predicate)
do {
let fetched = try context.fetch(fetchRequest)
return fetched
} catch {
print("ERROR FETCHING: ", error)
}
return []
// return (try? context.fetch(fetchRequest)) ?? []
}
func snackbar(_ message: String, undoAction: SnackbarUndoAction? = nil) {
@ -220,7 +205,7 @@ import Views
dataService.setItemLabels(itemID: item.unwrappedID, labels: InternalLinkedItemLabel.make(Set(existingLabels + [label]) as NSSet))
item.update(inContext: dataService.viewContext)
updateFeatureFilter(context: dataService.viewContext, filter: FeaturedItemFilter(rawValue: featureFilter))
fetcher.refreshFeatureItems(dataService: dataService)
}
}
@ -234,16 +219,12 @@ import Views
func pinItem(dataService: DataService, item: Models.LibraryItem) {
addLabel(dataService: dataService, item: item, label: "Pinned", color: "#0A84FF")
if featureFilter == FeaturedItemFilter.pinned.rawValue {
updateFeatureFilter(context: dataService.viewContext, filter: .pinned)
}
fetcher.refreshFeatureItems(dataService: dataService)
}
func unpinItem(dataService: DataService, item: Models.LibraryItem) {
removeLabel(dataService: dataService, item: item, named: "Pinned")
if featureFilter == FeaturedItemFilter.pinned.rawValue {
updateFeatureFilter(context: dataService.viewContext, filter: .pinned)
}
fetcher.refreshFeatureItems(dataService: dataService)
}
func markRead(dataService: DataService, item: Models.LibraryItem) {

View File

@ -17,33 +17,6 @@ import Views
action: { viewModel.itemUnderLabelEdit = item },
label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") }
)
// Button(action: {
// withAnimation(.linear(duration: 0.4)) {
// viewModel.setLinkArchived(
// dataService: dataService,
// objectID: item.objectID,
// archived: !item.isArchived
// )
// }
// }, label: {
// Label(
// item.isArchived ? "Unarchive" : "Archive",
// systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox"
// )
// })
// Button("Remove Item", role: .destructive) {
// viewModel.removeLink(dataService: dataService, objectID: item.objectID)
// }
// if let author = item.author {
// Button(
// action: {
// viewModel.filterState.searchTerm = "author:\"\(author)\""
// },
// label: {
// Label(String("More by \(author)"), systemImage: "person")
// }
// )
// }
} else {
Button(
action: { viewModel.recoverItem(dataService: dataService, itemID: item.unwrappedID) },

View File

@ -21,36 +21,6 @@ import SwiftUI
@AppStorage("inboxMenuState") var inboxMenuState = "open"
@AppStorage("followingMenuState") var followingMenuState = "open"
func createInboxViewModel(_ filter: InternalFilter) -> HomeFeedViewModel {
let result = HomeFeedViewModel(
folder: "inbox",
fetcher: LibraryItemFetcher(),
listConfig: LibraryListConfig(
hasFeatureCards: true,
leadingSwipeActions: [.pin],
trailingSwipeActions: [.archive, .delete],
cardStyle: .library
)
)
result.appliedFilter = filter
return result
}
func createFollowingViewModel(_ filter: InternalFilter) -> HomeFeedViewModel {
let result = HomeFeedViewModel(
folder: "following",
fetcher: LibraryItemFetcher(),
listConfig: LibraryListConfig(
hasFeatureCards: false,
leadingSwipeActions: [.moveToInbox],
trailingSwipeActions: [.archive, .delete],
cardStyle: .library
)
)
result.appliedFilter = filter
return result
}
var innerBody: some View {
ZStack {
NavigationLink("", destination: HomeView(viewModel: inboxViewModel), isActive: $inboxActive)

View File

@ -22,28 +22,6 @@ import Views
trackReadEvent()
}
func handleArchiveAction(dataService: DataService) {
guard let objectID = item?.objectID ?? pdfItem?.objectID else { return }
dataService.archiveLink(objectID: objectID, archived: !isItemArchived)
showInLibrarySnackbar(!isItemArchived ? "Link archived" : "Link unarchived")
}
func handleDeleteAction(dataService: DataService) {
guard let objectID = item?.objectID ?? pdfItem?.objectID else { return }
removeLibraryItemAction(dataService: dataService, objectID: objectID)
}
func updateItemReadStatus(dataService: DataService) {
guard let itemID = item?.unwrappedID ?? pdfItem?.itemID else { return }
dataService.updateLinkReadingProgress(
itemID: itemID,
readingProgress: isItemRead ? 0 : 100,
anchorIndex: 0,
force: false
)
}
private func trackReadEvent() {
guard let itemID = item?.unwrappedID ?? pdfItem?.itemID else { return }
guard let slug = item?.unwrappedSlug ?? pdfItem?.slug else { return }