diff --git a/Meshtastic/Extensions/Logger.swift b/Meshtastic/Extensions/Logger.swift index 74dcdb4a..925da350 100644 --- a/Meshtastic/Extensions/Logger.swift +++ b/Meshtastic/Extensions/Logger.swift @@ -25,29 +25,30 @@ extension Logger { static let statistics = Logger(subsystem: subsystem, category: "📈 Stats") /// Fetch from the logstore - static public func fetch(since date: Date, predicateFormat: String) async throws -> [String] { + static public func fetch(since date: Date, predicateFormat: String) async throws -> [OSLogEntryLog] { let store = try OSLogStore(scope: .currentProcessIdentifier) let position = store.position(date: date) let predicate = NSPredicate(format: predicateFormat) let entries = try store.getEntries(at: position, matching: predicate) - var logs: [String] = [] + var logs: [OSLogEntryLog] = [] for entry in entries { try Task.checkCancellation() if let log = entry as? OSLogEntryLog { - logs.append(""" - \(entry.date.formatted(.dateTime.hour(.twoDigits(amPM: .omitted)).minute().second().secondFraction(.fractional(3)))) \(log.level.description) \ - \(log.category) \(entry.composedMessage)\n - """) + logs.append(log) +// logs.append(""" +// \(entry.date.formatted(.dateTime.hour(.twoDigits(amPM: .omitted)).minute().second().secondFraction(.fractional(3)))) \(log.level.description) \ +// \(log.category) \(entry.composedMessage)\n +// """) } else { - logs.append("\(entry.date): \(entry.composedMessage)\n") + // logs.append("\(entry.date): \(entry.composedMessage)\n") } } - if logs.isEmpty { logs = ["Nothing found"] } + if logs.isEmpty { logs = [] } return logs } } diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index 32fc88d9..3f9cda69 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -85,15 +85,15 @@ import OSLog if smartPostion { let age = -location.timestamp.timeIntervalSinceNow if age > 10 { - Logger.services.warning("📍 Bad Location \(self.count): Too Old \(age) seconds ago \(location)") + Logger.services.warning("📍 Bad Location \(self.count): Too Old \(age) seconds ago \(location, privacy: .private)") return false } if location.horizontalAccuracy < 0 { - Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location)") + Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") return false } if location.horizontalAccuracy > 5 { - Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location)") + Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") return false } } diff --git a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift index 8cfcb612..48e71904 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift @@ -74,7 +74,8 @@ struct PositionPopover: View { .padding(.bottom, 5) /// Altitude Label { - Text("Altitude: \(distanceFormatter.string(fromDistance: Double(position.altitude)))") + let altitude = Measurement(value: Double(position.altitude), unit: UnitLength.meters) + Text("Altitude: \(altitude.formatted())") .foregroundColor(.primary) } icon: { Image(systemName: "mountain.2.fill") diff --git a/Meshtastic/Views/Settings/AppLog.swift b/Meshtastic/Views/Settings/AppLog.swift index 7ec291a7..e697b86a 100644 --- a/Meshtastic/Views/Settings/AppLog.swift +++ b/Meshtastic/Views/Settings/AppLog.swift @@ -8,47 +8,60 @@ import SwiftUI import OSLog +@available(iOS 17.4, *) struct AppLog: View { - @State private var text = "Loading..." - + + @State private var logs: [OSLogEntryLog] = [] + @State private var sortOrder = [KeyPathComparator(\OSLogEntryLog.date)] + @State private var selection = Set() + private var idiom : UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + var body: some View { - ScrollView { - Text(text) - .textSelection(.enabled) - .fontDesign(.monospaced) - .font(.caption2) - .padding() + + Table(logs, selection: $selection, sortOrder: $sortOrder) { + if idiom != .phone { + TableColumn("Date", value: \.date) { value in + Text("\(value.date, format: .dateTime)") + } + .width(min: 150, max: 200) + TableColumn("Category", value: \.category) + .width(min: 100, max: 125) + } + TableColumn("Message", value: \.composedMessage) + .width(ideal: 200, max: .infinity) + } + .onChange(of: sortOrder) { _, sortOrder in + logs.sort(using: sortOrder) } .task { - text = await fetchLogs() + logs = await fetchLogs() + } + .presentationCompactAdaptation(.fullScreenCover) + } +} + +@available(iOS 17.4, *) +extension AppLog { + static private let template = NSPredicate(format: "(subsystem BEGINSWITH $PREFIX) || ((subsystem IN $SYSTEM) && ((messageType == error) || (messageType == fault)))") + + @MainActor + private func fetchLogs() async -> [OSLogEntryLog] { + let calendar = Calendar.current + guard let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date.now) else { + return [] + } + do { + let predicate = AppLog.template.withSubstitutionVariables( + [ + "PREFIX": "gvh.MeshtasticClient", + "SYSTEM": ["com.apple.coredata"] + ]) + let logs = try await Logger.fetch(since: dayAgo, predicateFormat: predicate.predicateFormat) + return logs + } catch { + return [] } } } -extension AppLog { - static private let template = NSPredicate(format: - "(subsystem BEGINSWITH $PREFIX) || ((subsystem IN $SYSTEM) && ((messageType == error) || (messageType == fault)))") - - @MainActor - private func fetchLogs() async -> String { - let calendar = Calendar.current - guard let dayAgo = calendar.date(byAdding: .day, - value: -1, to: Date.now) else { - return "Invalid calendar" - } - - do { - let predicate = AppLog.template.withSubstitutionVariables( - [ - "PREFIX": "gvh.MeshtasticClient", - "SYSTEM": ["com.apple.coredata"] - ]) - - let logs = try await Logger.fetch(since: dayAgo, - predicateFormat: predicate.predicateFormat) - return logs.joined() - } catch { - return error.localizedDescription - } - } -} +extension OSLogEntry: Identifiable { } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index dda4f5ba..115c66c2 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -425,16 +425,18 @@ struct Settings: View { } .tag(SettingsSidebar.adminMessageLog) #if DEBUG - NavigationLink { - AppLog() - } label: { - Label { - Text("Debug Logs") - } icon: { - Image(systemName: "building.columns") + if #available (iOS 17.4, *) { + NavigationLink { + AppLog() + } label: { + Label { + Text("Debug Logs") + } icon: { + Image(systemName: "building.columns") + } } + .tag(SettingsSidebar.appLog) } - .tag(SettingsSidebar.appLog) #endif } Section(header: Text("Firmware")) {