bugger/Sources/ViewModels/BugStore.swift

109 lines
3.0 KiB
Swift

import Foundation
@Observable
final class BugStore {
static let shared = BugStore()
private(set) var bugs: [Bug] = []
private(set) var unseenBugs: Set<String> = []
private(set) var lastUpdated: Date?
private(set) var isLoading = false
private(set) var error: Error?
var activeBugs: [Bug] {
bugs.filter { $0.status != .closed && $0.status != .resolved }
}
var unseenActiveCount: Int {
activeBugs.filter { unseenBugs.contains($0.id) }.count
}
var bugsSortedByPriority: [Bug] {
activeBugs.sorted { lhs, rhs in
if lhs.priority != rhs.priority {
return lhs.priority < rhs.priority
}
return lhs.createdAt < rhs.createdAt
}
}
private init() {
unseenBugs = AppStateService.shared.persistedSeenBugs
}
func update(with newBugs: [Bug]) {
let oldBugs = bugs
let oldIDs = Set(oldBugs.map(\.id))
let newIDs = Set(newBugs.map(\.id))
let added = newIDs.subtracting(oldIDs)
unseenBugs.formUnion(added)
let changes = detectChanges(old: oldBugs, new: newBugs)
if !changes.isEmpty {
Task {
await NotificationService.shared.handleChanges(changes)
}
}
bugs = newBugs
lastUpdated = Date()
error = nil
AppStateService.shared.updateSeenBugs(unseenBugs)
}
func markSeen(_ bugID: String) {
unseenBugs.remove(bugID)
AppStateService.shared.updateSeenBugs(unseenBugs)
}
func markAllSeen() {
unseenBugs.removeAll()
AppStateService.shared.updateSeenBugs(unseenBugs)
}
func setLoading(_ loading: Bool) {
isLoading = loading
}
func setError(_ error: Error?) {
self.error = error
}
private func detectChanges(old: [Bug], new: [Bug]) -> [BugChange] {
let oldMap = Dictionary(uniqueKeysWithValues: old.map { ($0.id, $0) })
var changes: [BugChange] = []
for newBug in new {
guard let oldBug = oldMap[newBug.id] else {
changes.append(
BugChange(type: .newBug, bug: newBug, oldStatus: nil, oldAssignee: nil)
)
continue
}
if oldBug.status != newBug.status {
changes.append(
BugChange(type: .statusChanged, bug: newBug, oldStatus: oldBug.status, oldAssignee: nil)
)
}
if oldBug.priority != newBug.priority {
changes.append(
BugChange(type: .priorityChanged, bug: newBug, oldStatus: nil, oldAssignee: nil)
)
}
if oldBug.assignee != newBug.assignee {
changes.append(
BugChange(
type: .assigneeChanged,
bug: newBug,
oldStatus: nil,
oldAssignee: oldBug.assignee
)
)
}
}
return changes
}
}