mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
132 lines
3.8 KiB
Swift
132 lines
3.8 KiB
Swift
// The MIT License (MIT)
|
|
//
|
|
// Copyright (c) 2020-2026 Alexander Grebenyuk (github.com/kean).
|
|
|
|
import SwiftUI
|
|
import Pulse
|
|
import CoreData
|
|
import Combine
|
|
|
|
package struct ConsoleMessageCell: View {
|
|
package let message: LoggerMessageEntity
|
|
package var isDisclosureNeeded = false
|
|
|
|
@ScaledMetric(relativeTo: .body) private var fontMultiplier = 17.0
|
|
@ObservedObject private var settings: UserSettings = .shared
|
|
|
|
package init(message: LoggerMessageEntity, isDisclosureNeeded: Bool = false) {
|
|
self.message = message
|
|
self.isDisclosureNeeded = isDisclosureNeeded
|
|
}
|
|
|
|
package var body: some View {
|
|
let contents = VStack(alignment: .leading, spacing: 4) {
|
|
header.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
|
|
Text(message.text)
|
|
.font(contentFont)
|
|
.foregroundColor(.textColor(for: message.logLevel))
|
|
.lineLimit(settings.lineLimit)
|
|
}
|
|
if #unavailable(iOS 16) {
|
|
contents.padding(.vertical, 4)
|
|
} else {
|
|
contents
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var header: some View {
|
|
HStack {
|
|
Text(title)
|
|
.lineLimit(1)
|
|
.font(.footnote)
|
|
.foregroundColor(titleColor)
|
|
Spacer()
|
|
#if !os(watchOS)
|
|
if message.isPinned {
|
|
BookmarkIconView()
|
|
}
|
|
ConsoleTimestampView(timestamp: message.formattedTimestamp)
|
|
.padding(.trailing, 3)
|
|
#endif
|
|
}
|
|
.overlay(alignment: .trailing) {
|
|
if isDisclosureNeeded {
|
|
ListDisclosureIndicator()
|
|
.offset(x: 8, y: 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
private var title: String {
|
|
var title = message.logLevel.name.capitalized
|
|
if message.label != "default" {
|
|
title += "・\(message.label.capitalized)"
|
|
}
|
|
return title
|
|
}
|
|
|
|
var titleColor: Color {
|
|
message.logLevel >= .warning ? .textColor(for: message.logLevel) : .secondary
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
private var contentFont: Font {
|
|
let baseSize = CGFloat(settings.listDisplayOptions.content.fontSize)
|
|
return Font.system(size: baseSize * (fontMultiplier / 17.0))
|
|
}
|
|
|
|
private var detailsFont: Font {
|
|
let baseSize = CGFloat(settings.listDisplayOptions.header.fontSize)
|
|
return Font.system(size: baseSize * (fontMultiplier / 17.0)).monospacedDigit()
|
|
}
|
|
|
|
static let timeFormatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "en_US")
|
|
formatter.dateFormat = "HH:mm:ss.SSS"
|
|
return formatter
|
|
}()
|
|
}
|
|
|
|
struct ListDisclosureIndicator: View {
|
|
var body: some View {
|
|
Image(systemName: "chevron.right")
|
|
.lineLimit(1)
|
|
.font(.caption2.weight(.bold))
|
|
.foregroundColor(.secondary.opacity(0.33))
|
|
}
|
|
}
|
|
|
|
extension UXColor {
|
|
package static func textColor(for level: LoggerStore.Level) -> UXColor {
|
|
switch level {
|
|
case .trace: return .secondaryLabel
|
|
case .debug, .info: return .label
|
|
case .notice, .warning: return .systemOrange
|
|
case .error, .critical: return .red
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Color {
|
|
package static func textColor(for level: LoggerStore.Level) -> Color {
|
|
switch level {
|
|
case .trace: return .secondary
|
|
case .debug, .info: return .primary
|
|
case .notice, .warning: return .orange
|
|
case .error, .critical: return .red
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
@available(iOS 18, tvOS 18, macOS 15, watchOS 11, visionOS 1, *)
|
|
#Preview(traits: .sizeThatFitsLayout) {
|
|
ConsoleMessageCell(message: try! LoggerStore.mock.messages()[0])
|
|
.injecting(ConsoleEnvironment(store: LoggerStore.mock))
|
|
.padding()
|
|
}
|
|
#endif
|