mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
use fetched results controller to manage linked item list
This commit is contained in:
parent
23173e6f0b
commit
36083c1f7b
1 changed files with 63 additions and 26 deletions
|
|
@ -5,9 +5,11 @@ import SwiftUI
|
|||
import Utils
|
||||
import Views
|
||||
|
||||
@MainActor final class HomeFeedViewModel: ObservableObject {
|
||||
@MainActor final class HomeFeedViewModel: NSObject, ObservableObject {
|
||||
var currentDetailViewModel: LinkItemDetailViewModel?
|
||||
|
||||
private var fetchedResultsController: NSFetchedResultsController<LinkedItem>?
|
||||
|
||||
@Published var items = [LinkedItem]()
|
||||
@Published var isLoading = false
|
||||
@Published var showPushNotificationPrimer = false
|
||||
|
|
@ -29,8 +31,6 @@ import Views
|
|||
var searchIdx = 0
|
||||
var receivedIdx = 0
|
||||
|
||||
init() {}
|
||||
|
||||
func itemAppeared(item: LinkedItem, dataService: DataService) async {
|
||||
if isLoading { return }
|
||||
let itemIndex = items.firstIndex(where: { $0.id == item.id })
|
||||
|
|
@ -81,42 +81,73 @@ import Views
|
|||
}
|
||||
return itemObjects
|
||||
}()
|
||||
items = isRefresh ? newItems : items + newItems
|
||||
|
||||
if searchTerm.replacingOccurrences(of: " ", with: "").isEmpty {
|
||||
updateFetchController(dataService: dataService)
|
||||
} else {
|
||||
// Don't use FRC for searching. Use server results directly.
|
||||
if fetchedResultsController != nil {
|
||||
fetchedResultsController = nil
|
||||
items = []
|
||||
}
|
||||
items = isRefresh ? newItems : items + newItems
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
receivedIdx = thisSearchIdx
|
||||
cursor = queryResult.cursor
|
||||
await dataService.prefetchPages(itemIDs: newItems.map(\.unwrappedID))
|
||||
showLoadingBar = false
|
||||
} else if searchTerm.replacingOccurrences(of: " ", with: "").isEmpty {
|
||||
await dataService.viewContext.perform {
|
||||
let fetchRequest: NSFetchRequest<Models.LinkedItem> = LinkedItem.fetchRequest()
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \LinkedItem.savedAt, ascending: false)]
|
||||
if let predicate = LinkedItemFilter(rawValue: self.appliedFilter)?.predicate {
|
||||
fetchRequest.predicate = predicate
|
||||
}
|
||||
// // TODO: Filter on label
|
||||
|
||||
if let fetchedItems = try? dataService.viewContext.fetch(fetchRequest) {
|
||||
self.items = fetchedItems
|
||||
self.cursor = nil
|
||||
self.isLoading = false
|
||||
}
|
||||
}
|
||||
showLoadingBar = false
|
||||
}
|
||||
|
||||
showLoadingBar = false
|
||||
}
|
||||
|
||||
private var fetchRequest: NSFetchRequest<Models.LinkedItem> {
|
||||
let fetchRequest: NSFetchRequest<Models.LinkedItem> = LinkedItem.fetchRequest()
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \LinkedItem.savedAt, ascending: false)]
|
||||
|
||||
var subPredicates = [NSPredicate]()
|
||||
|
||||
subPredicates.append((LinkedItemFilter(rawValue: appliedFilter) ?? .inbox).predicate)
|
||||
|
||||
if !selectedLabels.isEmpty {
|
||||
var labelSubPredicates = [NSPredicate]()
|
||||
|
||||
for label in selectedLabels {
|
||||
labelSubPredicates.append(
|
||||
NSPredicate(format: "SUBQUERY(labels, $label, $label.id == \"\(label.unwrappedID)\").@count > 0")
|
||||
)
|
||||
}
|
||||
|
||||
subPredicates.append(NSCompoundPredicate(orPredicateWithSubpredicates: labelSubPredicates))
|
||||
}
|
||||
|
||||
fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: subPredicates)
|
||||
return fetchRequest
|
||||
}
|
||||
|
||||
private func updateFetchController(dataService: DataService) {
|
||||
fetchedResultsController = NSFetchedResultsController(
|
||||
fetchRequest: fetchRequest,
|
||||
managedObjectContext: dataService.viewContext,
|
||||
sectionNameKeyPath: nil,
|
||||
cacheName: nil
|
||||
)
|
||||
|
||||
guard let fetchedResultsController = fetchedResultsController else {
|
||||
return
|
||||
}
|
||||
|
||||
fetchedResultsController.delegate = self
|
||||
try? fetchedResultsController.performFetch()
|
||||
}
|
||||
|
||||
func setLinkArchived(dataService: DataService, objectID: NSManagedObjectID, archived: Bool) {
|
||||
// TODO: remove this by making list always fetch from Coredata
|
||||
guard let itemIndex = items.firstIndex(where: { $0.objectID == objectID }) else { return }
|
||||
items.remove(at: itemIndex)
|
||||
dataService.archiveLink(objectID: objectID, archived: archived)
|
||||
Snackbar.show(message: archived ? "Link archived" : "Link moved to Inbox")
|
||||
}
|
||||
|
||||
func removeLink(dataService: DataService, objectID: NSManagedObjectID) {
|
||||
guard let itemIndex = items.firstIndex(where: { $0.objectID == objectID }) else { return }
|
||||
items.remove(at: itemIndex)
|
||||
Snackbar.show(message: "Link removed")
|
||||
dataService.removeLink(objectID: objectID)
|
||||
}
|
||||
|
|
@ -160,3 +191,9 @@ import Views
|
|||
return query
|
||||
}
|
||||
}
|
||||
|
||||
extension HomeFeedViewModel: NSFetchedResultsControllerDelegate {
|
||||
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||
items = controller.fetchedObjects as? [LinkedItem] ?? []
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue