mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Logging and linting
This commit is contained in:
parent
b131714c5f
commit
fc97247b8c
20 changed files with 158 additions and 181 deletions
|
|
@ -53,12 +53,12 @@ public extension FileManager {
|
|||
do {
|
||||
accumulatedSize += try contentItemURL.regularFileAllocatedSize()
|
||||
} catch {
|
||||
Logger.services.error("💥 File Manager Error: \(error.localizedDescription)")
|
||||
Logger.services.error("💥 File Manager Error: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
|
||||
}
|
||||
if let error = enumeratorError {
|
||||
Logger.services.error("💥 AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription)")
|
||||
Logger.services.error("💥 AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
|
||||
return Double(accumulatedSize).toBytes
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ extension Logger {
|
|||
|
||||
/// The logger's subsystem.
|
||||
private static var subsystem = Bundle.main.bundleIdentifier!
|
||||
|
||||
|
||||
/// All admin messages
|
||||
static let admin = Logger(subsystem: subsystem, category: "🏛 Admin")
|
||||
|
||||
|
|
@ -20,28 +20,27 @@ extension Logger {
|
|||
|
||||
/// All logs related to the mesh
|
||||
static let mesh = Logger(subsystem: subsystem, category: "🕸️ Mesh")
|
||||
|
||||
|
||||
/// All logs related to MQTT
|
||||
static let mqtt = Logger(subsystem: subsystem, category: "📱 MQTT")
|
||||
|
||||
|
||||
/// All detailed logs originating from the device (radio).
|
||||
static let radio = Logger(subsystem: subsystem, category: "📟 Radio")
|
||||
|
||||
|
||||
/// All logs related to services such as network calls, location, etc.
|
||||
static let services = Logger(subsystem: subsystem, category: "🍏 Services")
|
||||
|
||||
/// All logs related to tracking and analytics.
|
||||
static let statistics = Logger(subsystem: subsystem, category: "📊 Stats")
|
||||
|
||||
|
||||
/// Fetch from the logstore
|
||||
static public func fetch(predicateFormat: String) async throws -> [OSLogEntryLog] {
|
||||
|
||||
let store = try OSLogStore(scope: .currentProcessIdentifier)
|
||||
let position = store.position(timeIntervalSinceLatestBoot: 0)
|
||||
//let calendar = Calendar.current
|
||||
//let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date.now)
|
||||
//let position = store.position(date: dayAgo!)
|
||||
// let calendar = Calendar.current
|
||||
// let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date.now)
|
||||
// let position = store.position(date: dayAgo!)
|
||||
let predicate = NSPredicate(format: predicateFormat)
|
||||
let entries = try store.getEntries(at: position, matching: predicate)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
|
||||
extension URL {
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ extension URL {
|
|||
do {
|
||||
return try FileManager.default.attributesOfItem(atPath: path)
|
||||
} catch let error as NSError {
|
||||
print("FileAttribute error: \(error)")
|
||||
Logger.services.error("FileAttribute error: \(error, privacy: . public)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
func startScanning() {
|
||||
if isSwitchedOn {
|
||||
centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
|
||||
Logger.services.info("✅ Scanning Started")
|
||||
Logger.services.info("✅ [BLE] Scanning Started")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
func stopScanning() {
|
||||
if centralManager.isScanning {
|
||||
centralManager.stopScan()
|
||||
Logger.services.info("🛑 Stopped Scanning")
|
||||
Logger.services.info("🛑 [BLE] Stopped Scanning")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
self.timeoutTimerCount = 0
|
||||
self.startScanning()
|
||||
} else {
|
||||
Logger.services.info("🚨 BLE Connecting 2 Second Timeout Timer Fired \(self.timeoutTimerCount) Time(s): \(name)")
|
||||
Logger.services.info("🚨 [BLE] Connecting 2 Second Timeout Timer Fired \(self.timeoutTimerCount, privacy: .public) Time(s): \(name, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
self.automaticallyReconnect = true
|
||||
}
|
||||
if connectedPeripheral != nil {
|
||||
Logger.services.info("ℹ️ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.info("ℹ️ [BLE] Disconnecting from: \(self.connectedPeripheral.name, privacy: .public) to connect to \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
disconnectPeripheral()
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
let context = ["name": "\(peripheral.name ?? "Unknown")"]
|
||||
timeoutTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true)
|
||||
RunLoop.current.add(timeoutTimer!, forMode: .common)
|
||||
Logger.services.info("ℹ️ BLE Connecting: \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.info("ℹ️ BLE Connecting: \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
}
|
||||
|
||||
// Disconnect Connected Peripheral
|
||||
|
|
@ -203,13 +203,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
// Discover Services
|
||||
peripheral.discoverServices([meshtasticServiceCBUUID])
|
||||
Logger.services.info("✅ BLE Connected: \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.info("✅ [BLE] Connected: \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
}
|
||||
|
||||
// Called when a Peripheral fails to connect
|
||||
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
|
||||
cancelPeripheralConnection()
|
||||
Logger.services.error("🚫 BLE Failed to Connect: \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.error("🚫 [BLE] Failed to Connect: \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
}
|
||||
|
||||
// Disconnect Peripheral Event
|
||||
|
|
@ -225,7 +225,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
if errorCode == 6 { // CBError.Code.connectionTimeout The connection has timed out unexpectedly.
|
||||
// Happens when device is manually reset / powered off
|
||||
lastConnectionError = "🚨" + String.localizedStringWithFormat("ble.errorcode.6 %@".localized, e.localizedDescription)
|
||||
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
|
||||
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
|
||||
} else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us.
|
||||
// Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work.
|
||||
if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString {
|
||||
|
|
@ -242,11 +242,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
manager.schedule()
|
||||
}
|
||||
lastConnectionError = "🚨 \(e.localizedDescription)"
|
||||
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
|
||||
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
|
||||
} else if errorCode == 14 { // Peer removed pairing information
|
||||
// Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that
|
||||
lastConnectionError = "🚨 " + String.localizedStringWithFormat("ble.errorcode.14 %@".localized, e.localizedDescription)
|
||||
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(self.lastConnectionError)")
|
||||
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode, privacy: .public) Error: \(self.lastConnectionError, privacy: .public)")
|
||||
} else {
|
||||
if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString {
|
||||
manager.notifications = [
|
||||
|
|
@ -262,12 +262,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
manager.schedule()
|
||||
}
|
||||
lastConnectionError = "🚨 \(e.localizedDescription)"
|
||||
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
|
||||
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
// Disconnected without error which indicates user intent to disconnect
|
||||
// Happens when swiping to disconnect
|
||||
Logger.services.info("ℹ️ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect")
|
||||
Logger.services.info("ℹ️ [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public): User Initiated Disconnect")
|
||||
}
|
||||
// Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake
|
||||
self.startScanning()
|
||||
|
|
@ -276,12 +276,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
// MARK: Peripheral Services functions
|
||||
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
|
||||
if let error {
|
||||
Logger.services.error("🚫 Discover Services error \(error.localizedDescription)")
|
||||
Logger.services.error("🚫 [BLE] Discover Services error \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
guard let services = peripheral.services else { return }
|
||||
for service in services where service.uuid == meshtasticServiceCBUUID {
|
||||
peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID, LOGRADIO_UUID], for: service)
|
||||
Logger.services.info("✅ BLE Service for Meshtastic discovered by \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.info("✅ [BLE] Service for Meshtastic discovered by \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
|
||||
if let error {
|
||||
Logger.services.error("🚫 BLE Discover Characteristics error for \(peripheral.name ?? "Unknown") \(error.localizedDescription) disconnecting device")
|
||||
Logger.services.error("🚫 [BLE] Discover Characteristics error for \(peripheral.name ?? "Unknown", privacy: .public) \(error.localizedDescription, privacy: .public) disconnecting device")
|
||||
// Try and stop crashes when this error occurs
|
||||
disconnectPeripheral()
|
||||
return
|
||||
|
|
@ -313,7 +313,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
Logger.services.info("✅ [BLE] did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
FROMNUM_characteristic = characteristic
|
||||
peripheral.setNotifyValue(true, for: characteristic)
|
||||
|
||||
|
||||
case LOGRADIO_UUID:
|
||||
Logger.services.info("✅ [BLE] did discover LOGRADIO (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
LOGRADIO_characteristic = characteristic
|
||||
|
|
@ -341,7 +341,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
func onMqttDisconnected() {
|
||||
mqttProxyConnected = false
|
||||
Logger.services.info("MQTT Disconnected")
|
||||
Logger.services.info("📲 MQTT Disconnected")
|
||||
}
|
||||
|
||||
func onMqttMessageReceived(message: CocoaMQTTMessage) {
|
||||
|
|
@ -456,14 +456,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
do {
|
||||
try context!.save()
|
||||
Logger.data.info("💾 Saved TraceRoute sent to node: \(String(receivingNode?.user?.longName ?? "unknown".localized))")
|
||||
Logger.data.info("💾 Saved TraceRoute sent to node: \(String(receivingNode?.user?.longName ?? "unknown".localized), privacy: .public)")
|
||||
} catch {
|
||||
context!.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Updating Core Data BluetoothConfigEntity: \(nsError)")
|
||||
Logger.data.error("Error Updating Core Data BluetoothConfigEntity: \(nsError, privacy: .public)")
|
||||
}
|
||||
|
||||
let logString = String.localizedStringWithFormat("mesh.log.traceroute.sent %@".localized, String(destNum))
|
||||
let logString = String.localizedStringWithFormat("mesh.log.traceroute.sent %@".localized, destNum.toHex())
|
||||
MeshLogger.log("🪧 \(logString)")
|
||||
|
||||
} catch {
|
||||
|
|
@ -512,14 +512,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
if let error {
|
||||
|
||||
Logger.services.error("🚫 didUpdateValueFor Characteristic error \(error.localizedDescription)")
|
||||
Logger.services.error("🚫 [BLE] didUpdateValueFor Characteristic error \(error.localizedDescription, privacy: .public)")
|
||||
let errorCode = (error as NSError).code
|
||||
if errorCode == 5 || errorCode == 15 {
|
||||
// BLE PIN connection errors
|
||||
// 5 CBATTErrorDomain Code=5 "Authentication is insufficient."
|
||||
// 15 CBATTErrorDomain Code=15 "Encryption is insufficient."
|
||||
lastConnectionError = "🚨" + String.localizedStringWithFormat("ble.errorcode.pin %@".localized, error.localizedDescription)
|
||||
Logger.services.error("\(error.localizedDescription) Please try connecting again and check the PIN carefully.")
|
||||
Logger.services.error("\(error.localizedDescription, privacy: .public) Please try connecting again and check the PIN carefully.")
|
||||
self.disconnectPeripheral(reconnect: false)
|
||||
}
|
||||
return
|
||||
|
|
@ -527,7 +527,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
switch characteristic.uuid {
|
||||
case LOGRADIO_UUID:
|
||||
if (characteristic.value == nil || characteristic.value!.isEmpty) {
|
||||
if characteristic.value == nil || characteristic.value!.isEmpty {
|
||||
return
|
||||
}
|
||||
let coordsSearch = Regex {
|
||||
|
|
@ -547,32 +547,30 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
.anchorsMatchLineEndings()
|
||||
if var log = String(data: characteristic.value!, encoding: .utf8) {
|
||||
|
||||
/// Debug Log Level
|
||||
if (log.starts(with: "DEBUG |")) {
|
||||
if log.starts(with: "DEBUG |") {
|
||||
do {
|
||||
let logString = log
|
||||
if let coordsMatch = try coordsSearch.firstMatch(in: logString) {
|
||||
log = "\(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces))"
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.debug("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)")
|
||||
}else {
|
||||
} else {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.debug("🐞 \(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.debug("🐞 \(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
}
|
||||
} else if (log.starts(with: "INFO |")) {
|
||||
} else if log.starts(with: "INFO |") {
|
||||
do {
|
||||
let logString = log
|
||||
if let coordsMatch = try coordsSearch.firstMatch(in: logString) {
|
||||
log = "\(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces))"
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.info("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)")
|
||||
} else {
|
||||
} else {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.debug("🐞 \(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
}
|
||||
|
|
@ -580,18 +578,18 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.info("✅ \(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
}
|
||||
} else if (log.starts(with: "WARN |")) {
|
||||
} else if log.starts(with: "WARN |") {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.warning("⚠️ \(log.replacingOccurrences(of: "WARN |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
} else if (log.starts(with: "ERROR |")) {
|
||||
} else if log.starts(with: "ERROR |") {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.error("💥 \(log.replacingOccurrences(of: "ERROR |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
} else if (log.starts(with: "CRIT |")) {
|
||||
} else if log.starts(with: "CRIT |") {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.critical("💥 \(log.replacingOccurrences(of: "CRIT |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
|
||||
} else {
|
||||
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
|
||||
Logger.radio.debug("📟 \(log)")
|
||||
Logger.radio.debug("📟 \(log, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +604,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
decodedInfo = try FromRadio(serializedData: characteristic.value!)
|
||||
|
||||
} catch {
|
||||
Logger.services.error("\(error.localizedDescription) \(characteristic.value!)")
|
||||
Logger.services.error("💥 \(error.localizedDescription, privacy: .public) \(characteristic.value!, privacy: .public)")
|
||||
}
|
||||
|
||||
// Publish mqttClientProxyMessages received on the from radio
|
||||
|
|
@ -651,9 +649,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
UserDefaults.preferredPeripheralNum = Int(myInfo?.myNodeNum ?? 0)
|
||||
context!.reset()
|
||||
connectTo(peripheral: peripheral)
|
||||
Logger.data.notice("🗂️ Restored Core data for /\(UserDefaults.preferredPeripheralNum)")
|
||||
Logger.data.notice("🗂️ Restored Core data for /\(UserDefaults.preferredPeripheralNum, privacy: .public)")
|
||||
} catch {
|
||||
Logger.data.error("Copy error: \(error)")
|
||||
Logger.data.error("🗂️ Restore Core data copy error: \(error, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -823,7 +821,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
} catch {
|
||||
context!.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Updating Core Data TraceRouteHOp: \(nsError)")
|
||||
Logger.data.error("Error Updating Core Data TraceRouteHOp: \(nsError, privacy: .public)")
|
||||
}
|
||||
let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.route %@".localized, routeString)
|
||||
MeshLogger.log("🪧 \(logString)")
|
||||
|
|
@ -850,7 +848,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
invalidVersion = false
|
||||
lastConnectionError = ""
|
||||
isSubscribed = true
|
||||
Logger.mesh.info("🤜 Want Config Complete. ID:\(decodedInfo.configCompleteID)")
|
||||
Logger.mesh.info("[BLE] 🤜 Want Config Complete. ID:\(decodedInfo.configCompleteID)")
|
||||
peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected })
|
||||
// Config conplete returns so we don't read the characteristic again
|
||||
|
||||
|
|
@ -904,9 +902,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
|
||||
case FROMNUM_UUID:
|
||||
Logger.services.info("🗞️ BLE (Notify) characteristic, value will be read next")
|
||||
Logger.services.info("🗞️ [BLE] (Notify) characteristic, value will be read next")
|
||||
default:
|
||||
Logger.services.error("Unhandled Characteristic UUID: \(characteristic.uuid)")
|
||||
Logger.services.error("🚫 Unhandled Characteristic UUID: \(characteristic.uuid, privacy: .public)")
|
||||
}
|
||||
if FROMRADIO_characteristic != nil {
|
||||
// Either Read the config complete value or from num notify value
|
||||
|
|
@ -1010,18 +1008,18 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected {
|
||||
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
|
||||
let logString = String.localizedStringWithFormat("mesh.log.textmessage.sent %@ %@ %@".localized, String(newMessage.messageId), String(fromUserNum), String(toUserNum))
|
||||
let logString = String.localizedStringWithFormat("mesh.log.textmessage.sent %@ %@ %@".localized, String(newMessage.messageId), fromUserNum.toHex(), toUserNum.toHex())
|
||||
|
||||
MeshLogger.log("💬 \(logString)")
|
||||
do {
|
||||
try context!.save()
|
||||
Logger.data.info("💾 Saved a new sent message from \(self.connectedPeripheral.num) to \(toUserNum)")
|
||||
Logger.data.info("💾 Saved a new sent message from \(self.connectedPeripheral.num.toHex(), privacy: .public) to \(toUserNum.toHex(), privacy: .public)")
|
||||
success = true
|
||||
|
||||
} catch {
|
||||
context!.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Unresolved Core Data error in Send Message Function your database is corrupted running a node db reset should clean up the data. Error: \(nsError)")
|
||||
Logger.data.error("Unresolved Core Data error in Send Message Function your database is corrupted running a node db reset should clean up the data. Error: \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1088,11 +1086,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
do {
|
||||
try context!.save()
|
||||
Logger.data.info("💾 Updated Waypoint from Waypoint App Packet From: \(fromNodeNum)")
|
||||
Logger.data.info("💾 Updated Waypoint from Waypoint App Packet From: \(fromNodeNum.toHex(), privacy: .public)")
|
||||
} catch {
|
||||
context!.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Saving NodeInfoEntity from WAYPOINT_APP \(nsError)")
|
||||
Logger.data.error("Error Saving NodeInfoEntity from WAYPOINT_APP \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
return success
|
||||
|
|
@ -2950,7 +2948,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected {
|
||||
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
|
||||
Logger.mesh.debug("📮 Sent a request for a Store & Forward Client History to \(toUser.num) for the last \(120) minutes.")
|
||||
Logger.mesh.debug("📮 Sent a request for a Store & Forward Client History to \(toUser.num.toHex(), privacy: .public) for the last \(120, privacy: .public) minutes.")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
@ -2961,9 +2959,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
// Handle each of the store and forward request / response messages
|
||||
switch storeAndForwardMessage.rr {
|
||||
case .unset:
|
||||
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerError:
|
||||
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerHeartbeat:
|
||||
/// When we get a router heartbeat we know there is a store and forward node on the network
|
||||
/// Check if it is the primary S&F Router and save the timestamp of the last heartbeat so that we can show the request message history menu item on node long press if the router has been seen recently
|
||||
|
|
@ -2991,13 +2989,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
Logger.data.error("Save Store and Forward Router Error")
|
||||
}
|
||||
}
|
||||
MeshLogger.log("💓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("💓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerPing:
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerPong:
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerBusy:
|
||||
MeshLogger.log("🐝 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🐝 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerHistory:
|
||||
/// Set the Router History Last Request Value
|
||||
guard let routerNode = getNodeInfo(id: Int64(packet.from), context: context) else {
|
||||
|
|
@ -3017,28 +3015,28 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
context.rollback()
|
||||
Logger.data.error("Save Store and Forward Router Error")
|
||||
}
|
||||
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerStats:
|
||||
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientError:
|
||||
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientHistory:
|
||||
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientStats:
|
||||
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientPing:
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientPong:
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .clientAbort:
|
||||
MeshLogger.log("🛑 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("🛑 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .UNRECOGNIZED:
|
||||
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
case .routerTextDirect:
|
||||
MeshLogger.log("💬 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("💬 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
textMessageAppPacket(packet: packet, wantRangeTestPackets: false, connectedNode: connectedNodeNum, storeForward: true, context: context)
|
||||
case .routerTextBroadcast:
|
||||
MeshLogger.log("✉️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
|
||||
MeshLogger.log("✉️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
|
||||
textMessageAppPacket(packet: packet, wantRangeTestPackets: false, connectedNode: connectedNodeNum, storeForward: true, context: context)
|
||||
}
|
||||
}
|
||||
|
|
@ -3058,11 +3056,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
do {
|
||||
try context!.save()
|
||||
} catch {
|
||||
Logger.data.error("Failed to clear existing channels from local app database: \(error.localizedDescription)")
|
||||
Logger.data.error("Failed to clear existing channels from local app database: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription)")
|
||||
Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3098,7 +3096,7 @@ extension BLEManager: CBCentralManagerDelegate {
|
|||
default:
|
||||
status = "default"
|
||||
}
|
||||
Logger.services.debug("📜 BLEManager status: \(status)")
|
||||
Logger.services.debug("📜 [BLE] Bluetooth status: \(status)")
|
||||
}
|
||||
|
||||
// Called each time a peripheral is discovered
|
||||
|
|
@ -3106,7 +3104,7 @@ extension BLEManager: CBCentralManagerDelegate {
|
|||
|
||||
if self.automaticallyReconnect && peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" {
|
||||
self.connectTo(peripheral: peripheral)
|
||||
Logger.services.info("BLE Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown")")
|
||||
Logger.services.info("✅ [BLE] Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
}
|
||||
let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
||||
let device = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: name ?? "Unknown", shortName: "?", longName: name ?? "Unknown", firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class LocalNotificationManager {
|
|||
UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
|
||||
|
||||
for notification in notifications {
|
||||
Logger.services.debug("\(notification)")
|
||||
Logger.services.debug("\(notification, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,6 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
|
|||
|
||||
}
|
||||
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
||||
Logger.services.error("Location manager error: \(error.localizedDescription)")
|
||||
Logger.services.error("Location manager error: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import OSLog
|
|||
if self.manager.authorizationStatus == .notDetermined {
|
||||
self.manager.requestWhenInUseAuthorization()
|
||||
}
|
||||
Logger.services.info("📍 Starting location updates")
|
||||
Logger.services.info("📍 [App] Starting location updates")
|
||||
Task {
|
||||
do {
|
||||
self.updatesStarted = true
|
||||
|
|
@ -70,14 +70,14 @@ import OSLog
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.services.error("💥 Could not start location updates: \(error.localizedDescription)")
|
||||
Logger.services.error("💥 [App] Could not start location updates: \(error.localizedDescription)")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func stopLocationUpdates() {
|
||||
Logger.services.info("🛑 Stopping location updates")
|
||||
Logger.services.info("🛑 [App] Stopping location updates")
|
||||
self.updatesStarted = false
|
||||
}
|
||||
|
||||
|
|
@ -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("📍 [App] Bad Location \(self.count, privacy: .public): Too Old \(age, privacy: .public) 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("📍 [App] Bad Location \(self.count, privacy: .public): 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("📍 [App] Bad Location \(self.count, privacy: .public): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class OfflineTileManager: ObservableObject {
|
|||
}
|
||||
|
||||
init() {
|
||||
Logger.services.debug("Documents Directory = \(self.documentsDirectory.absoluteString)")
|
||||
Logger.services.debug("Documents Directory = \(self.documentsDirectory.absoluteString, privacy: .public)")
|
||||
createDirectoriesIfNecessary()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ class MeshLogger {
|
|||
} else {
|
||||
try data.write(to: logFile, options: .atomicWrite)
|
||||
let log = String(data: data, encoding: .utf8) ?? "unknown".localized
|
||||
Logger.mesh.notice("\(log)")
|
||||
Logger.mesh.notice("\(log, privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
Logger.mesh.error("Error writing mesh log data: \(error.localizedDescription)")
|
||||
Logger.mesh.error("Error writing mesh log data: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
myInfoEntity.rebootCount = Int32(myInfo.rebootCount)
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))")
|
||||
Logger.data.info("💾 Saved a new myInfo for node: \(myInfo.myNodeNum.toHex(), privacy: .public)")
|
||||
return myInfoEntity
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Inserting New Core Data MyInfoEntity: \(nsError)")
|
||||
Logger.data.error("💥 Error Inserting New Core Data MyInfoEntity: \(nsError, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
@ -127,16 +127,16 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
|
||||
Logger.data.info("💾 Updated myInfo for node: \(myInfo.myNodeNum.toHex(), privacy: .public)")
|
||||
return fetchedMyInfo[0]
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Updating Core Data MyInfoEntity: \(nsError)")
|
||||
Logger.data.error("💥 Error Updating Core Data MyInfoEntity: \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("Fetch MyInfo Error")
|
||||
Logger.data.error("💥 Fetch MyInfo Error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -185,16 +185,16 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
Logger.data.error("Failed to save channel: \(error.localizedDescription)")
|
||||
Logger.data.error("💥 Failed to save channel: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
Logger.data.info("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
|
||||
} else if channel.role.rawValue > 0 {
|
||||
Logger.data.error("Trying to save a channel to a MyInfo that does not exist: \(fromNum)")
|
||||
Logger.data.error("💥Trying to save a channel to a MyInfo that does not exist: \(fromNum.toHex(), privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
|
||||
Logger.data.error("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
if metadata.isInitialized {
|
||||
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, String(fromNum))
|
||||
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, fromNum.toHex())
|
||||
MeshLogger.log("🏷️ \(logString)")
|
||||
|
||||
let fetchedNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
|
|
@ -238,13 +238,13 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
|
|||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
Logger.data.error("Failed to save device metadata: \(error.localizedDescription)")
|
||||
Logger.data.error("💥 Failed to save device metadata: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
Logger.data.info("💾 Updated Device Metadata from Admin App Packet For: \(fromNum)")
|
||||
Logger.data.info("💾 Updated Device Metadata from Admin App Packet For: \(fromNum.toHex(), privacy: .public)")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
|
||||
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -415,19 +415,19 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
}
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 NodeInfo saved for \(nodeInfo.num)")
|
||||
Logger.data.info("💾 [NodeInfo] saved for \(nodeInfo.num.toHex(), privacy: .public)")
|
||||
return fetchedNode[0]
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError)")
|
||||
Logger.data.error("💥 Error Saving Core Data NodeInfoEntity: \(nsError, privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("Fetch MyInfo Error")
|
||||
Logger.data.error("💥 Fetch MyInfo Error")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("Fetch NodeInfoEntity Error")
|
||||
Logger.data.error("💥 Fetch NodeInfoEntity Error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -442,7 +442,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
|
||||
if !cmmc.messages.isEmpty {
|
||||
|
||||
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, String(packet.from))
|
||||
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, packet.from.toHex())
|
||||
MeshLogger.log("🥫 \(logString)")
|
||||
|
||||
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
|
|
@ -460,15 +460,15 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
fetchedNode[0].cannedMessageConfig?.messages = messages
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
|
||||
Logger.data.info("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num.toHex(), privacy: .public)")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
|
||||
Logger.data.error("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("Error Deserializing ADMIN_APP packet.")
|
||||
Logger.data.error("💥 Error Deserializing ADMIN_APP packet.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class MqttClientProxyManager {
|
|||
|
||||
extension MqttClientProxyManager: CocoaMQTTDelegate {
|
||||
func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
|
||||
Logger.mqtt.info("📲 MQTT Client Proxy didConnectAck: \(ack)")
|
||||
Logger.mqtt.info("📲 [MQTT Client Proxy] didConnectAck: \(ack, privacy: .public)")
|
||||
if ack == .accept {
|
||||
delegate?.onMqttConnected()
|
||||
} else {
|
||||
|
|
@ -112,7 +112,7 @@ extension MqttClientProxyManager: CocoaMQTTDelegate {
|
|||
case .accept:
|
||||
errorDescription = "No Error"
|
||||
case .unacceptableProtocolVersion:
|
||||
errorDescription = "Proto ver"
|
||||
errorDescription = "Unacceptable Protocol version"
|
||||
case .identifierRejected:
|
||||
errorDescription = "Invalid Id"
|
||||
case .serverUnavailable:
|
||||
|
|
@ -124,13 +124,13 @@ extension MqttClientProxyManager: CocoaMQTTDelegate {
|
|||
default:
|
||||
errorDescription = "Unknown Error"
|
||||
}
|
||||
Logger.services.error("\(errorDescription)")
|
||||
Logger.services.error("📲 [MQTT Client Proxy] \(errorDescription, privacy: .public)")
|
||||
delegate?.onMqttError(message: errorDescription)
|
||||
self.disconnect()
|
||||
}
|
||||
}
|
||||
func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) {
|
||||
Logger.mqtt.debug("📲 [MQTT Client Proxy] disconnected: \(err?.localizedDescription ?? "")")
|
||||
Logger.mqtt.debug("📲 [MQTT Client Proxy] disconnected: \(err?.localizedDescription ?? "", privacy: .public)")
|
||||
if let error = err {
|
||||
delegate?.onMqttError(message: error.localizedDescription)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import OSLog
|
|||
|
||||
class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
Logger.services.info("🚀 Meshtstic Apple App launched!")
|
||||
Logger.services.info("🚀 [App] Meshtstic Apple App launched!")
|
||||
// Default User Default Values
|
||||
UserDefaults.standard.register(defaults: ["meshMapRecentering": true])
|
||||
UserDefaults.standard.register(defaults: ["meshMapShowNodeHistory": true])
|
||||
|
|
|
|||
|
|
@ -90,13 +90,11 @@ extension NSManagedObjectContext {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Created by Tom Harrington on 5/12/20.
|
||||
// Copyright © 2020 Atomic Bird LLC. All rights reserved.
|
||||
// Gist from https://atomicbird.com/blog/core-data-back-up-store/
|
||||
//
|
||||
extension NSPersistentContainer {
|
||||
|
||||
enum CopyPersistentStoreErrors: Error {
|
||||
case invalidDestination(String)
|
||||
case destinationError(String)
|
||||
|
|
@ -104,9 +102,8 @@ extension NSPersistentContainer {
|
|||
case copyStoreError(String)
|
||||
case invalidSource(String)
|
||||
}
|
||||
|
||||
|
||||
/// Restore a persistent store for a URL `backupURL`.
|
||||
///
|
||||
/// **Be very careful with this**. To restore a persistent store, the current persistent store must be removed from the container. When that happens, **all currently loaded Core Data objects** will become invalid. Using them after restoring will cause your app to crash. When calling this method you **must** ensure that you do not continue to use any previously fetched managed objects or existing fetched results controllers. **If this method does not throw, that does not mean your app is safe.** You need to take extra steps to prevent crashes. The details vary depending on the nature of your app.
|
||||
/// - Parameter backupURL: A file URL containing backup copies of all currently loaded persistent stores.
|
||||
/// - Throws: `CopyPersistentStoreError` in various situations.
|
||||
|
|
@ -115,7 +112,7 @@ extension NSPersistentContainer {
|
|||
guard backupURL.isFileURL else {
|
||||
throw CopyPersistentStoreErrors.invalidSource("Backup URL must be a file URL")
|
||||
}
|
||||
|
||||
|
||||
for persistentStoreDescription in persistentStoreDescriptions {
|
||||
guard let loadedStoreURL = persistentStoreDescription.url else {
|
||||
continue
|
||||
|
|
@ -127,7 +124,7 @@ extension NSPersistentContainer {
|
|||
let storeOptions = persistentStoreDescription.options
|
||||
let configurationName = persistentStoreDescription.configuration
|
||||
let storeType = persistentStoreDescription.type
|
||||
|
||||
|
||||
// Replace the current store with the backup copy. This has a side effect of removing the current store from the Core Data stack.
|
||||
// When restoring, it's necessary to use the current persistent store coordinator.
|
||||
try persistentStoreCoordinator.replacePersistentStore(at: loadedStoreURL, destinationOptions: storeOptions, withPersistentStoreFrom: backupURL, sourceOptions: storeOptions, ofType: storeType)
|
||||
|
|
@ -138,7 +135,7 @@ extension NSPersistentContainer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Copy all loaded persistent stores to a new directory. Each currently loaded file-based persistent store will be copied (including journal files, external binary storage, and anything else Core Data needs) into the destination directory to a persistent store with the same name and type as the existing store. In-memory stores, if any, are skipped.
|
||||
/// - Parameters:
|
||||
/// - destinationURL: Destination for new persistent store files. Must be a file URL. If `overwriting` is `false` and `destinationURL` exists, it must be a directory.
|
||||
|
|
@ -146,15 +143,15 @@ extension NSPersistentContainer {
|
|||
/// - Throws: `CopyPersistentStoreError`
|
||||
/// - Returns: Nothing. If no errors are thrown, all loaded persistent stores will be copied to the destination directory.
|
||||
func copyPersistentStores(to destinationURL: URL, overwriting: Bool = false) throws -> Void {
|
||||
print(destinationURL)
|
||||
|
||||
guard !destinationURL.relativeString.contains("/0/") else {
|
||||
throw CopyPersistentStoreErrors.invalidDestination("Invalid 0 Node Id")
|
||||
}
|
||||
|
||||
|
||||
guard destinationURL.isFileURL else {
|
||||
throw CopyPersistentStoreErrors.invalidDestination("Destination URL must be a file URL")
|
||||
}
|
||||
|
||||
|
||||
// If the destination exists and we aren't overwriting it, then it must be a directory. (If we are overwriting, we'll remove it anyway, so it doesn't matter whether it's a directory).
|
||||
var isDirectory: ObjCBool = false
|
||||
if !overwriting && FileManager.default.fileExists(atPath: destinationURL.path, isDirectory: &isDirectory) {
|
||||
|
|
@ -171,14 +168,14 @@ extension NSPersistentContainer {
|
|||
throw CopyPersistentStoreErrors.destinationNotRemoved("Can't overwrite destination at \(destinationURL)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the destination directory
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
throw CopyPersistentStoreErrors.destinationError("Could not create destination directory at \(destinationURL)")
|
||||
}
|
||||
|
||||
|
||||
for persistentStoreDescription in persistentStoreDescriptions {
|
||||
guard let storeURL = persistentStoreDescription.url else {
|
||||
continue
|
||||
|
|
@ -195,7 +192,7 @@ extension NSPersistentContainer {
|
|||
do {
|
||||
let newStore = try temporaryPSC.addPersistentStore(ofType: persistentStoreDescription.type, configurationName: persistentStoreDescription.configuration, at: persistentStoreDescription.url, options: persistentStoreDescription.options)
|
||||
let _ = try temporaryPSC.migratePersistentStore(newStore, to: destinationStoreURL, options: persistentStoreDescription.options, withType: persistentStoreDescription.type)
|
||||
|
||||
|
||||
/// Cleanup extra files
|
||||
let directory = destinationStoreURL.deletingLastPathComponent()
|
||||
/// Delete -wal file
|
||||
|
|
@ -205,13 +202,13 @@ extension NSPersistentContainer {
|
|||
do {
|
||||
try FileManager.default.removeItem(at: directory.appendingPathComponent("Meshtastic.sqlite-shm"))
|
||||
} catch {
|
||||
print(error)
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-shm file \(error, privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-wal file \(error, privacy: .public)")
|
||||
}
|
||||
|
||||
} catch {
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite file \(error, privacy: .public)")
|
||||
throw CopyPersistentStoreErrors.copyStoreError("\(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ struct Connect: View {
|
|||
Text("Short Name: \(node?.user?.shortName ?? "?")")
|
||||
Text("Long Name: \(node?.user?.longName ?? "unknown".localized)")
|
||||
Text("BLE RSSI: \(connectedPeripheral.rssi)")
|
||||
|
||||
|
||||
Button {
|
||||
if !bleManager.sendShutdown(fromUser: node!.user!, toUser: node!.user!, adminIndex: node!.myInfo!.adminIndex) {
|
||||
Logger.mesh.error("Shutdown Failed")
|
||||
|
|
@ -214,18 +214,17 @@ struct Connect: View {
|
|||
if let connectedPeripheral = bleManager.connectedPeripheral, connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral()
|
||||
}
|
||||
//clearCoreDataDatabase(context: context, includeRoutes: false)
|
||||
let container = NSPersistentContainer(name : "Meshtastic")
|
||||
// clearCoreDataDatabase(context: context, includeRoutes: false)
|
||||
let container = NSPersistentContainer(name: "Meshtastic")
|
||||
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
Logger.data.error("nil File path for back")
|
||||
return
|
||||
}
|
||||
do {
|
||||
try container.copyPersistentStores(to: url.appendingPathComponent("backup").appendingPathComponent("\(UserDefaults.preferredPeripheralNum)"), overwriting: true)
|
||||
|
||||
Logger.data.notice("🗂️ Made a core data backup to backup/\(UserDefaults.preferredPeripheralNum)")
|
||||
} catch {
|
||||
print("Copy error: \(error)")
|
||||
Logger.data.error("🗂️ Core data backup copy error: \(error, privacy: .public)")
|
||||
}
|
||||
UserDefaults.preferredPeripheralId = selectedPeripherialId
|
||||
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId })
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import CoreData
|
|||
import Foundation
|
||||
|
||||
struct AppData: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@State private var files = [URL]()
|
||||
|
|
@ -19,10 +19,9 @@ struct AppData: View {
|
|||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Button(action: {
|
||||
let container = NSPersistentContainer(name : "Meshtastic")
|
||||
let container = NSPersistentContainer(name: "Meshtastic")
|
||||
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
Logger.data.error("nil File path for back")
|
||||
return
|
||||
|
|
@ -32,9 +31,8 @@ struct AppData: View {
|
|||
loadFiles()
|
||||
Logger.data.notice("🗂️ Made a core data backup to backup/\(UserDefaults.preferredPeripheralNum)")
|
||||
} catch {
|
||||
print("Copy error: \(error)")
|
||||
Logger.data.error("🗂️ Core data backup copy error: \(error, privacy: .public)")
|
||||
}
|
||||
|
||||
}) {
|
||||
Label {
|
||||
Text("Backup Database")
|
||||
|
|
@ -49,26 +47,25 @@ struct AppData: View {
|
|||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
|
||||
}
|
||||
List(files, id: \.self) { file in
|
||||
HStack {
|
||||
VStack (alignment: .leading ) {
|
||||
if file.pathExtension.contains("sqlite") { //} == "sqlite" {
|
||||
VStack(alignment: .leading ) {
|
||||
if file.pathExtension.contains("sqlite") {
|
||||
Label {
|
||||
Text("Node Core Data Backup \(file.pathComponents[9])/\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
|
||||
.swipeActions {
|
||||
Button(role: .none) {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
let container = NSPersistentContainer(name : "Meshtastic")
|
||||
let container = NSPersistentContainer(name: "Meshtastic")
|
||||
do {
|
||||
context.reset()
|
||||
try container.restorePersistentStore(from: file.absoluteURL)
|
||||
UserDefaults.preferredPeripheralId = ""
|
||||
UserDefaults.preferredPeripheralNum = Int(file.pathComponents[10]) ?? 0
|
||||
Logger.data.notice("🗂️ Restored a core data backup to backup/\(UserDefaults.preferredPeripheralNum)")
|
||||
Logger.data.notice("🗂️ Restored a core data backup to backup/\(UserDefaults.preferredPeripheralNum, privacy: .public)")
|
||||
} catch {
|
||||
print("Copy error: \(error)")
|
||||
Logger.data.error("🗂️ Core data restore copy error: \(error, privacy: .public)")
|
||||
}
|
||||
} label: {
|
||||
Label("restore", systemImage: "arrow.counterclockwise")
|
||||
|
|
@ -77,7 +74,7 @@ struct AppData: View {
|
|||
do {
|
||||
try FileManager.default.removeItem(at: file)
|
||||
} catch {
|
||||
print(error)
|
||||
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
|
||||
}
|
||||
} label: {
|
||||
Label("delete", systemImage: "trash")
|
||||
|
|
@ -89,8 +86,7 @@ struct AppData: View {
|
|||
.font(idiom == .phone ? .callout : .title)
|
||||
.frame(width: 35)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Label {
|
||||
Text("\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
|
||||
.swipeActions {
|
||||
|
|
@ -98,13 +94,12 @@ struct AppData: View {
|
|||
do {
|
||||
try FileManager.default.removeItem(at: file)
|
||||
} catch {
|
||||
print(error)
|
||||
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
|
||||
}
|
||||
} label: {
|
||||
Label("delete", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
|
||||
} icon: {
|
||||
Image(systemName: "doc.text")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
|
@ -115,13 +110,13 @@ struct AppData: View {
|
|||
}
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Spacer()
|
||||
VStack (alignment: .trailing) {
|
||||
Button() {
|
||||
VStack(alignment: .trailing) {
|
||||
Button {
|
||||
do {
|
||||
try FileManager.default.removeItem(at: file)
|
||||
loadFiles()
|
||||
} catch {
|
||||
print(error)
|
||||
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
|
||||
}
|
||||
} label: {
|
||||
Label("", systemImage: "trash")
|
||||
|
|
@ -136,7 +131,7 @@ struct AppData: View {
|
|||
})
|
||||
.listStyle(.inset)
|
||||
}
|
||||
|
||||
|
||||
private func loadFiles() {
|
||||
files = []
|
||||
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
|
|
@ -146,11 +141,13 @@ struct AppData: View {
|
|||
if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
|
||||
for case let fileURL as URL in enumerator {
|
||||
do {
|
||||
let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey])
|
||||
let fileAttributes = try fileURL.resourceValues(forKeys: [.isRegularFileKey])
|
||||
if fileAttributes.isRegularFile! {
|
||||
files.append(fileURL)
|
||||
}
|
||||
} catch { print(error, fileURL) }
|
||||
} catch {
|
||||
Logger.services.error("📁 Load file: \(fileURL, privacy: .public) error: \(error, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct AppLog: View {
|
|||
@State var isExporting = false
|
||||
@State var exportString = ""
|
||||
@State var isEditingFilters = false
|
||||
|
||||
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
private let dateFormatStyle = Date.FormatStyle()
|
||||
.hour(.twoDigits(amPM: .omitted))
|
||||
|
|
@ -45,7 +45,6 @@ struct AppLog: View {
|
|||
Text(value.level.description)
|
||||
}
|
||||
.width(min: 75, max: 100)
|
||||
|
||||
}
|
||||
TableColumn("log.message", value: \.composedMessage) { value in
|
||||
Text(value.composedMessage)
|
||||
|
|
@ -167,7 +166,6 @@ struct AppLog: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func didDismiss() {
|
||||
selection = nil
|
||||
selectedLog = nil
|
||||
|
|
@ -200,7 +198,6 @@ extension AppLog {
|
|||
let levelPredicate = NSPredicate(format: "messageType == %@", LogLevels(rawValue: level)?.level ?? "info")
|
||||
predicates.append(levelPredicate)
|
||||
}
|
||||
|
||||
if predicates.count > 0 || !searchText.isEmpty {
|
||||
if !searchText.isEmpty {
|
||||
let filterPredicates = NSCompoundPredicate(type: .and, subpredicates: predicates)
|
||||
|
|
@ -214,10 +211,8 @@ extension AppLog {
|
|||
}
|
||||
} else {
|
||||
let logs = try await Logger.fetch(predicateFormat: subsystemPredicate.predicateFormat)
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,13 +87,13 @@ struct AppSettings: View {
|
|||
do {
|
||||
try FileManager.default.removeItem(at: url.appendingPathComponent("Meshtastic.sqlite-shm"))
|
||||
} catch {
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-shm file \(error)")
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-shm file \(error, privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-wal file \(error)")
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite-wal file \(error, privacy: .public)")
|
||||
}
|
||||
} catch {
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite file \(error)")
|
||||
Logger.services.error("Error Deleting Meshtastic.sqlite file \(error, privacy: .public)")
|
||||
}
|
||||
}
|
||||
clearCoreDataDatabase(context: context, includeRoutes: true)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ struct BluetoothConfig: View {
|
|||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $deviceLoggingEnabled) {
|
||||
Label("Device Logging Enabled", systemImage: "ladybug")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ enum LogCategories: Int, CaseIterable, Identifiable {
|
|||
case radio = 4
|
||||
case services = 5
|
||||
case stats = 6
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
switch self {
|
||||
|
|
@ -81,16 +81,15 @@ enum LogLevels: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
|
||||
struct AppLogFilter: View {
|
||||
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
/// Filters
|
||||
var filterTitle = "App Log Filters"
|
||||
//@Binding
|
||||
@Binding var category: Int
|
||||
@Binding var level: Int
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section(header: Text(filterTitle)) {
|
||||
|
|
@ -100,13 +99,12 @@ struct AppLogFilter: View {
|
|||
Text("All Categories")
|
||||
.tag(-1)
|
||||
ForEach(LogCategories.allCases) { lc in
|
||||
Text("\(lc.description)")
|
||||
|
||||
Text("\(lc.description)")
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
}
|
||||
|
||||
|
||||
HStack {
|
||||
Label("Level", systemImage: "stairs")
|
||||
Picker("", selection: $level) {
|
||||
|
|
@ -114,8 +112,6 @@ struct AppLogFilter: View {
|
|||
.tag(-1)
|
||||
ForEach(LogLevels.allCases) { ll in
|
||||
Text("\(ll.description)")
|
||||
//.tag(ll.rawValue)
|
||||
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
|
|
|||
|
|
@ -9,14 +9,12 @@ import SwiftUI
|
|||
import MapKit
|
||||
import OSLog
|
||||
|
||||
//@available(iOS 17.0, macOS 14.0, *)
|
||||
struct LogDetail: View {
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
var log: OSLogEntryLog
|
||||
var font: Font = .title2
|
||||
|
||||
private let dateFormatStyle = Date.FormatStyle()
|
||||
.day(.defaultDigits)
|
||||
.month(.defaultDigits)
|
||||
|
|
@ -122,7 +120,6 @@ struct LogDetail: View {
|
|||
.textSelection(.enabled)
|
||||
.font(idiom == .phone ? .body : .title)
|
||||
.padding(.bottom, 5)
|
||||
|
||||
} icon: {
|
||||
Image(systemName: "text.bubble")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
|
@ -133,7 +130,6 @@ struct LogDetail: View {
|
|||
|
||||
}
|
||||
.listStyle(.plain)
|
||||
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue