mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
118 lines
3.7 KiB
Swift
118 lines
3.7 KiB
Swift
// The MIT License (MIT)
|
||
//
|
||
// Copyright (c) 2020–2022 Alexander Grebenyuk (github.com/kean).
|
||
|
||
import CoreData
|
||
import Pulse
|
||
import Combine
|
||
import SwiftUI
|
||
|
||
final class ConsoleViewModel: NSObject, NSFetchedResultsControllerDelegate, ObservableObject {
|
||
#if os(iOS) || os(macOS)
|
||
let table: ConsoleTableViewModel
|
||
#endif
|
||
@Published private(set) var entities: [LoggerMessageEntity] = []
|
||
|
||
let details: ConsoleDetailsRouterViewModel
|
||
|
||
// Search criteria
|
||
let searchCriteria: ConsoleSearchCriteriaViewModel
|
||
@Published var isOnlyErrors: Bool = false
|
||
@Published var isOnlyNetwork: Bool = false
|
||
@Published var filterTerm: String = ""
|
||
|
||
var onDismiss: (() -> Void)?
|
||
|
||
private(set) var store: LoggerStore
|
||
private let controller: NSFetchedResultsController<LoggerMessageEntity>
|
||
private var isActive = false
|
||
private var latestSessionId: UUID?
|
||
private var cancellables: [AnyCancellable] = []
|
||
|
||
init(store: LoggerStore) {
|
||
self.store = store
|
||
self.details = ConsoleDetailsRouterViewModel()
|
||
|
||
let request = NSFetchRequest<LoggerMessageEntity>(entityName: "\(LoggerMessageEntity.self)")
|
||
request.fetchBatchSize = 100
|
||
request.relationshipKeyPathsForPrefetching = ["request"]
|
||
request.sortDescriptors = [NSSortDescriptor(keyPath: \LoggerMessageEntity.createdAt, ascending: false)]
|
||
|
||
self.controller = NSFetchedResultsController<LoggerMessageEntity>(fetchRequest: request, managedObjectContext: store.viewContext, sectionNameKeyPath: nil, cacheName: nil)
|
||
|
||
self.searchCriteria = ConsoleSearchCriteriaViewModel(store: store)
|
||
#if os(iOS) || os(macOS)
|
||
self.table = ConsoleTableViewModel(searchCriteriaViewModel: searchCriteria)
|
||
#endif
|
||
|
||
super.init()
|
||
|
||
controller.delegate = self
|
||
|
||
$filterTerm.throttle(for: 0.25, scheduler: RunLoop.main, latest: true).dropFirst().sink { [weak self] filterTerm in
|
||
self?.refresh(filterTerm: filterTerm)
|
||
}.store(in: &cancellables)
|
||
|
||
searchCriteria.dataNeedsReload.throttle(for: 0.5, scheduler: DispatchQueue.main, latest: true).sink { [weak self] in
|
||
self?.refreshNow()
|
||
}.store(in: &cancellables)
|
||
|
||
$isOnlyErrors.receive(on: DispatchQueue.main).dropFirst().sink { [weak self] _ in
|
||
self?.refreshNow()
|
||
}.store(in: &cancellables)
|
||
|
||
refreshNow()
|
||
}
|
||
|
||
// MARK: Appearance
|
||
|
||
func onAppear() {
|
||
isActive = true
|
||
reloadMessages()
|
||
}
|
||
|
||
func onDisappear() {
|
||
isActive = false
|
||
}
|
||
|
||
// MARK: Refresh
|
||
|
||
private func refreshNow() {
|
||
refresh(filterTerm: filterTerm)
|
||
}
|
||
|
||
private func refresh(filterTerm: String) {
|
||
// Get sessionId
|
||
if latestSessionId == nil {
|
||
latestSessionId = entities.first?.session
|
||
}
|
||
let sessionId = store === LoggerStore.shared ? LoggerStore.Session.current.id : latestSessionId
|
||
|
||
// Search messages
|
||
ConsoleSearchCriteria.update(request: controller.fetchRequest, filterTerm: filterTerm, criteria: searchCriteria.criteria, filters: searchCriteria.filters, sessionId: sessionId, isOnlyErrors: isOnlyErrors, isOnlyNetwork: isOnlyNetwork)
|
||
try? controller.performFetch()
|
||
|
||
reloadMessages()
|
||
}
|
||
|
||
// MARK: - NSFetchedResultsControllerDelegate
|
||
|
||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith diff: CollectionDifference<NSManagedObjectID>) {
|
||
guard isActive else { return }
|
||
|
||
#if os(iOS) || os(macOS)
|
||
self.table.diff = diff
|
||
#endif
|
||
withAnimation {
|
||
reloadMessages()
|
||
}
|
||
}
|
||
|
||
private func reloadMessages() {
|
||
entities = controller.fetchedObjects ?? []
|
||
#if os(iOS) || os(macOS)
|
||
table.entities = entities
|
||
#endif
|
||
}
|
||
}
|