Files
omnivore/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift
Jackson Harper e63b4f9b2c Abstract out fetching from view model so we can better handle multiple fetch folders
Rename LinkedItem to LibraryItem

More on following

Add new fetcher

Tab bar
2023-12-07 17:15:52 +08:00

123 lines
3.9 KiB
Swift

import CoreData
import Models
import Services
import SwiftUI
@MainActor public final class LabelsViewModel: ObservableObject {
let labelNameMaxLength = 64
@Published var isLoading = false
@Published var selectedLabels = [LinkedItemLabel]()
@Published var unselectedLabels = Set<LinkedItemLabel>()
@Published var labels = [LinkedItemLabel]()
@Published var showCreateLabelModal = false
@Published var labelSearchFilter = ZWSP
public init() {}
func setLabels(_ labels: [LinkedItemLabel]) {
self.labels = labels.sorted { left, right in
let aTrimmed = left.unwrappedName.trimmingCharacters(in: .whitespaces)
let bTrimmed = right.unwrappedName.trimmingCharacters(in: .whitespaces)
return aTrimmed.caseInsensitiveCompare(bTrimmed) == .orderedAscending
}
}
func loadLabels(
dataService: DataService,
item: Models.LibraryItem? = nil,
highlight: Highlight? = nil,
initiallySelectedLabels: [LinkedItemLabel]? = nil
) async {
let selLabels = initiallySelectedLabels ?? item?.sortedLabels ?? highlight?.sortedLabels ?? []
await loadLabelsFromStore(dataService: dataService)
for label in labels {
if selLabels.contains(label) {
if !selectedLabels.contains(label) {
selectedLabels.append(label)
}
} else {
unselectedLabels.insert(label)
}
}
Task.detached(priority: .userInitiated) {
if let labelIDs = try? await dataService.labels() {
DispatchQueue.main.async {
dataService.viewContext.performAndWait {
self.setLabels(labelIDs.compactMap { dataService.viewContext.object(with: $0) as? LinkedItemLabel })
}
for label in self.labels {
if selLabels.contains(label) {
if !self.selectedLabels.contains(label) {
self.selectedLabels.append(label)
}
} else {
self.unselectedLabels.insert(label)
}
}
}
}
}
}
func loadLabelsFromStore(dataService: DataService) async {
let fetchRequest: NSFetchRequest<Models.LinkedItemLabel> = LinkedItemLabel.fetchRequest()
let fetchedLabels = await dataService.viewContext.perform {
try? fetchRequest.execute()
}
setLabels(fetchedLabels ?? [])
unselectedLabels = Set(fetchedLabels ?? [])
}
func fetchLabelsFromNetwork(dataService: DataService) async {
let labelIDs = try? await dataService.labels()
guard let labelIDs = labelIDs else { return }
let fetchedLabels = await dataService.viewContext.perform {
labelIDs.compactMap { dataService.viewContext.object(with: $0) as? LinkedItemLabel }
}
setLabels(fetchedLabels)
unselectedLabels = Set(fetchedLabels)
}
func createLabel(dataService: DataService, name: String, color: Color, description: String?) {
isLoading = true
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
guard let labelObjectID = try? dataService.createLabel(
name: trimmedName,
color: color.hex ?? "",
description: description
) else {
isLoading = false
return
}
if let label = dataService.viewContext.object(with: labelObjectID) as? LinkedItemLabel {
labels.insert(label, at: 0)
selectedLabels.append(label)
}
isLoading = false
showCreateLabelModal = false
}
func deleteLabel(dataService: DataService, labelID: String, name: String) {
dataService.removeLabel(labelID: labelID, name: name)
labels.removeAll { $0.name == name }
}
func saveItemLabelChanges(itemID: String, dataService: DataService) {
dataService.setItemLabels(itemID: itemID, labels: InternalLinkedItemLabel.make(Set(selectedLabels) as NSSet))
}
func saveHighlightLabelChanges(highlightID: String, dataService: DataService) {
dataService.setLabelsForHighlight(highlightID: highlightID, labelIDs: selectedLabels.map(\.unwrappedID))
}
}