mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
195 lines
5.8 KiB
Swift
195 lines
5.8 KiB
Swift
// The MIT License (MIT)
|
||
//
|
||
// Copyright (c) 2020–2022 Alexander Grebenyuk (github.com/kean).
|
||
|
||
import SwiftUI
|
||
import Pulse
|
||
import CoreData
|
||
import Combine
|
||
|
||
final class ConsoleMessageViewModel: Pinnable {
|
||
let title: String
|
||
let text: String
|
||
let textColor: Color
|
||
let badge: BadgeViewModel?
|
||
|
||
private let message: LoggerMessageEntity
|
||
private let searchCriteriaViewModel: ConsoleSearchCriteriaViewModel?
|
||
|
||
private(set) lazy var time = ConsoleMessageViewModel.timeFormatter.string(from: message.createdAt)
|
||
|
||
#if os(iOS)
|
||
lazy var textColor2 = UIColor.textColor(for: LoggerStore.Level(rawValue: message.level) ?? .debug)
|
||
lazy var attributedTitle: NSAttributedString = {
|
||
let string = NSMutableAttributedString()
|
||
let level = LoggerStore.Level(rawValue: message.level) ?? .debug
|
||
if let badge = badge {
|
||
string.append(badge.title, [.foregroundColor: UIColor.badgeColor(for: level)])
|
||
}
|
||
if message.label.name != "default" {
|
||
let prefix = badge == nil ? "" : " · "
|
||
string.append("\(prefix)\(message.label.name.capitalized)", [.foregroundColor: UIColor.secondaryLabel])
|
||
}
|
||
return string
|
||
}()
|
||
#endif
|
||
|
||
static let timeFormatter: DateFormatter = {
|
||
let formatter = DateFormatter()
|
||
formatter.locale = Locale(identifier: "en_US")
|
||
formatter.dateFormat = "HH:mm:ss.SSS"
|
||
return formatter
|
||
}()
|
||
|
||
private(set) lazy var pinViewModel = PinButtonViewModel(message: message)
|
||
|
||
init(message: LoggerMessageEntity, searchCriteriaViewModel: ConsoleSearchCriteriaViewModel? = nil) {
|
||
let time = ConsoleMessageViewModel.timeFormatter.string(from: message.createdAt)
|
||
if message.label.name == "default" {
|
||
self.title = time
|
||
} else {
|
||
self.title = "\(time) · \(message.label.name.capitalized)"
|
||
}
|
||
self.text = message.text
|
||
self.textColor = ConsoleMessageStyle.textColor(level: LoggerStore.Level(rawValue: message.level) ?? .debug)
|
||
self.badge = BadgeViewModel(message: message)
|
||
self.message = message
|
||
self.searchCriteriaViewModel = searchCriteriaViewModel
|
||
}
|
||
|
||
// MARK: Context Menu
|
||
|
||
#if os(iOS) || os(macOS)
|
||
func share() -> ShareItems {
|
||
ShareItems([ConsoleShareService.share(message)])
|
||
}
|
||
|
||
func copy() -> String {
|
||
message.text
|
||
}
|
||
|
||
var focusLabel: String {
|
||
message.label.name.capitalized
|
||
}
|
||
|
||
func focus() {
|
||
searchCriteriaViewModel?.criteria.labels.isEnabled = true
|
||
searchCriteriaViewModel?.criteria.labels.focused = message.label.name
|
||
}
|
||
|
||
func hide() {
|
||
searchCriteriaViewModel?.criteria.labels.isEnabled = true
|
||
searchCriteriaViewModel?.criteria.labels.hidden.insert(message.label.name)
|
||
}
|
||
#endif
|
||
}
|
||
|
||
private extension BadgeViewModel {
|
||
init?(message: LoggerMessageEntity) {
|
||
guard let model = LoggerStore.Level(rawValue: message.level).flatMap(BadgeViewModel.init) else {
|
||
return nil
|
||
}
|
||
self = model
|
||
}
|
||
|
||
init?(level: LoggerStore.Level) {
|
||
switch level {
|
||
case .critical, .error, .warning, .info, .notice:
|
||
self.init(title: level.name.uppercased(), color: .badgeColor(for: level))
|
||
case .debug, .trace:
|
||
return nil // Don't show
|
||
}
|
||
}
|
||
}
|
||
|
||
extension Color {
|
||
static func badgeColor(for level: LoggerStore.Level) -> Color {
|
||
switch level {
|
||
#if os(macOS)
|
||
case .error: return Color(Palette.red)
|
||
case .critical: return Color(Palette.red)
|
||
#else
|
||
case .critical: return .red
|
||
case .error: return .red
|
||
#endif
|
||
case .warning: return .orange
|
||
case .info: return .blue
|
||
case .notice: return .indigo
|
||
case .debug: return .primary
|
||
case .trace: return .primary
|
||
}
|
||
}
|
||
|
||
static func textColor(for level: LoggerStore.Level) -> Color {
|
||
switch level {
|
||
#if os(macOS)
|
||
case .error: return Color(Palette.red)
|
||
case .critical: return Color(Palette.red)
|
||
#else
|
||
case .critical: return .red
|
||
case .error: return .red
|
||
#endif
|
||
case .warning: return .orange
|
||
case .info: return .blue
|
||
case .notice: return .blue
|
||
case .debug: return .primary
|
||
case .trace: return .primary
|
||
}
|
||
}
|
||
}
|
||
|
||
#if os(iOS)
|
||
extension UIColor {
|
||
static func badgeColor(for level: LoggerStore.Level) -> UIColor {
|
||
switch level {
|
||
case .critical: return .systemRed
|
||
case .error: return .systemRed
|
||
case .warning: return .systemOrange
|
||
case .info: return .systemBlue
|
||
case .notice: return .systemBlue
|
||
case .debug: return .label
|
||
case .trace: return .label
|
||
}
|
||
}
|
||
|
||
static func textColor(for level: LoggerStore.Level) -> UIColor {
|
||
switch level {
|
||
case .trace: return .secondaryLabel
|
||
case .debug, .info: return .label
|
||
case .notice, .warning: return .systemOrange
|
||
case .error, .critical: return .systemRed
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if os(macOS)
|
||
enum ConsoleMessageStyle {
|
||
static func textColor(level: LoggerStore.Level) -> Color {
|
||
switch level {
|
||
case .trace: return .secondary
|
||
case .debug: return .primary
|
||
case .info: return .primary
|
||
case .notice: return .orange
|
||
case .warning: return .orange
|
||
case .error: return Color(Palette.red)
|
||
case .critical: return Color(Palette.red)
|
||
}
|
||
}
|
||
}
|
||
#else
|
||
enum ConsoleMessageStyle {
|
||
static func textColor(level: LoggerStore.Level) -> Color {
|
||
switch level {
|
||
case .trace: return .primary
|
||
case .debug: return .primary
|
||
case .info: return .primary
|
||
case .notice: return .orange
|
||
case .warning: return .orange
|
||
case .error: return .red
|
||
case .critical: return .red
|
||
}
|
||
}
|
||
}
|
||
#endif
|