mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
131 lines
3.4 KiB
Swift
131 lines
3.4 KiB
Swift
// The MIT License (MIT)
|
||
//
|
||
// Copyright (c) 2020–2023 Alexander Grebenyuk (github.com/kean).
|
||
|
||
import Foundation
|
||
import Pulse
|
||
import SwiftUI
|
||
import CoreData
|
||
|
||
enum LoggerEntity {
|
||
/// Regular log, not task attached.
|
||
case message(LoggerMessageEntity)
|
||
/// Either a log with an attached task, or a task itself.
|
||
case task(NetworkTaskEntity)
|
||
|
||
init(_ entity: NSManagedObject) {
|
||
if let message = entity as? LoggerMessageEntity {
|
||
if let task = message.task {
|
||
self = .task(task)
|
||
} else {
|
||
self = .message(message)
|
||
}
|
||
} else if let task = entity as? NetworkTaskEntity {
|
||
self = .task(task)
|
||
} else {
|
||
fatalError("Unsupported entity: \(entity)")
|
||
}
|
||
}
|
||
|
||
var task: NetworkTaskEntity? {
|
||
if case .task(let task) = self { return task }
|
||
return nil
|
||
}
|
||
}
|
||
|
||
extension LoggerMessageEntity: Identifiable {
|
||
public var id: NSManagedObjectID { objectID }
|
||
}
|
||
|
||
extension NetworkTaskEntity: Identifiable {
|
||
public var id: NSManagedObjectID { objectID }
|
||
}
|
||
|
||
extension NetworkTaskEntity {
|
||
var requestFileViewerContext: FileViewerViewModel.Context {
|
||
FileViewerViewModel.Context(
|
||
contentType: originalRequest?.contentType,
|
||
originalSize: requestBodySize,
|
||
metadata: metadata,
|
||
isResponse: false,
|
||
error: nil
|
||
)
|
||
}
|
||
|
||
var responseFileViewerContext: FileViewerViewModel.Context {
|
||
FileViewerViewModel.Context(
|
||
contentType: response?.contentType,
|
||
originalSize: responseBodySize,
|
||
metadata: metadata,
|
||
isResponse: true,
|
||
error: decodingError
|
||
)
|
||
}
|
||
}
|
||
|
||
extension LoggerMessageEntity {
|
||
var logLevel: LoggerStore.Level {
|
||
LoggerStore.Level(rawValue: level) ?? .debug
|
||
}
|
||
}
|
||
|
||
extension NetworkTaskEntity.State {
|
||
var tintColor: Color {
|
||
switch self {
|
||
case .pending: return .orange
|
||
case .success: return .green
|
||
case .failure: return .red
|
||
}
|
||
}
|
||
|
||
var iconSystemName: String {
|
||
switch self {
|
||
case .pending: return "clock.fill"
|
||
case .success: return "checkmark.circle.fill"
|
||
case .failure: return "exclamationmark.octagon.fill"
|
||
}
|
||
}
|
||
}
|
||
|
||
extension LoggerSessionEntity {
|
||
var formattedDate: String {
|
||
formattedDate(isCompact: false)
|
||
}
|
||
|
||
var searchTags: [String] {
|
||
possibleFormatters.map { $0.string(from: createdAt) }
|
||
}
|
||
|
||
func formattedDate(isCompact: Bool = false) -> String {
|
||
if isCompact {
|
||
return compactDateFormatter.string(from: createdAt)
|
||
} else {
|
||
return fullDateFormatter.string(from: createdAt)
|
||
}
|
||
}
|
||
|
||
var fullVersion: String? {
|
||
guard let version = version else {
|
||
return nil
|
||
}
|
||
if let build = build {
|
||
return version + " (\(build))"
|
||
}
|
||
return version
|
||
}
|
||
}
|
||
|
||
private let compactDateFormatter = DateFormatter(dateStyle: .none, timeStyle: .medium)
|
||
|
||
#if os(watchOS)
|
||
private let fullDateFormatter = DateFormatter(dateStyle: .short, timeStyle: .short, isRelative: true)
|
||
#else
|
||
private let fullDateFormatter = DateFormatter(dateStyle: .medium, timeStyle: .medium, isRelative: true)
|
||
#endif
|
||
|
||
private let possibleFormatters: [DateFormatter] = [
|
||
fullDateFormatter,
|
||
DateFormatter(dateStyle: .long, timeStyle: .none),
|
||
DateFormatter(dateStyle: .short, timeStyle: .none)
|
||
]
|