diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 99a00727..ad45481e 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -9017,7 +9017,7 @@ } }, "incomplete" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "de" : { "stringUnit" : { @@ -15216,6 +15216,9 @@ } } } + }, + "Model" : { + }, "module.configuration" : { "localizations" : { diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json index 1a8d07dc..a1a7444e 100644 --- a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Paper-Meshtastic-2 copy.jpg", + "filename" : "heltec-wireless-paper.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg deleted file mode 100644 index 36692599..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg new file mode 100644 index 00000000..cb3f188d --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg @@ -0,0 +1 @@ + diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json index 3b6b227c..d13152fe 100644 --- a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "images.png", + "filename" : "heltec-wireless-tracker.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg new file mode 100644 index 00000000..a5392595 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png deleted file mode 100644 index 4e9336c5..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json index aed717e4..dea94fc1 100644 --- a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "heltecwsl.png", + "filename" : "heltec-wsl-v3.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg new file mode 100644 index 00000000..1741223e --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png deleted file mode 100644 index 8881d0e1..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json b/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json new file mode 100644 index 00000000..0ecd041c --- /dev/null +++ b/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tbeam.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg b/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg new file mode 100644 index 00000000..cd0475c6 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json new file mode 100644 index 00000000..593dc16e --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-c6.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg b/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg new file mode 100644 index 00000000..8b626638 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json new file mode 100644 index 00000000..a5716fc8 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-t3s3-v1.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg new file mode 100644 index 00000000..1f8847d4 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Extensions/CoreData/UserEntityExtension.swift b/Meshtastic/Extensions/CoreData/UserEntityExtension.swift index 099d910d..662ca5b0 100644 --- a/Meshtastic/Extensions/CoreData/UserEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/UserEntityExtension.swift @@ -37,6 +37,8 @@ extension UserEntity { var hardwareImage: String? { guard let hwModel else { return nil } switch hwModel { + /// SVG Images for Vendors who are project backers + /// Heltec case "HELTECV3": return "HELTECV3" case "HELTECWIRELESSPAPER", "HELTECWIRELESSPAPERV10": @@ -45,18 +47,23 @@ extension UserEntity { return "HELTECWIRELESSTRACKER" case "HELTECWSLV3": return "HELTECWSLV3" + /// LilyGO + case "TBEAM", "TBEAM_V0P7": + return "TBEAM" + case "TLORAT3S3V1": + return "TLORAT3S3V1" + case "TLORAC6": + return "TLORAC6" + /// B&O Consulting case "NANOG1", "NANOG1EXPLORER": return "NANOG1" case "NANOG2ULTRA": return "NANOG2ULTRA" - case "RAK4631": - return "RAK4631" - case "RAK11200": - return "RAK11200" + case "STATIONG2": + return "STATIONG2" case "SOLAR_NODE": return "SOLAR_NODE" - case "STATIONG1": - return "STATIONG1" + case "UNPHONE": return "UNPHONE" default: diff --git a/Meshtastic/Resources/DeviceHardware.json b/Meshtastic/Resources/DeviceHardware.json index 94c74660..fd874357 100644 --- a/Meshtastic/Resources/DeviceHardware.json +++ b/Meshtastic/Resources/DeviceHardware.json @@ -294,7 +294,7 @@ "RAK" ], "images": [ - "rak4631.svg" + "rak11310.svg" ], "requiresDfu": true }, @@ -350,6 +350,9 @@ "displayName": "DIY V1", "tags": [ "DIY" + ], + "images": [ + "diy.svg" ] }, { @@ -427,10 +430,13 @@ "supportLevel": 3, "displayName": "Raspberry Pi Pico", "tags": [ - "Raspberry Pi", + "RPi", "DIY" ], - "requiresDfu": true + "requiresDfu": true, + "images": [ + "pico.svg" + ] }, { "hwModel": 47, @@ -441,10 +447,13 @@ "supportLevel": 3, "displayName": "Raspberry Pi Pico W", "tags": [ - "Raspberry Pi", + "RPi", "DIY" ], - "requiresDfu": true + "requiresDfu": true, + "images": [ + "rpipicow.svg" + ] }, { "hwModel": 48, diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index a9f7bcfe..0a648571 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -16,12 +16,16 @@ struct NodeDetail: View { formatter.unitsStyle = .full return formatter }() + var modemPreset: ModemPresets = ModemPresets( + rawValue: UserDefaults.modemPreset + ) ?? ModemPresets.longFast @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @State private var showingShutdownConfirm: Bool = false @State private var showingRebootConfirm: Bool = false @State private var dateFormatRelative: Bool = true + @State private var currentDevice: DeviceHardware? // The node the device is currently connected to var connectedNode: NodeInfoEntity? @@ -41,9 +45,37 @@ struct NodeDetail: View { ) Section("Hardware") { - NodeInfoItem(node: node) + NodeInfoItem(node: node, supported: currentDevice?.activelySupported ?? false) } Section("Node") { + HStack(alignment: .center) { + Spacer() + CircleText( + text: node.user?.shortName ?? "?", + color: Color(UIColor(hex: UInt32(node.num))), + circleSize: 75 + ) + if node.snr != 0 && !node.viaMqtt && node.hopsAway == 0 { + Spacer() + VStack { + let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: modemPreset) + LoRaSignalStrengthIndicator(signalStrength: signalStrength) + Text("Signal \(signalStrength.description)").font(.footnote) + Text("SNR \(String(format: "%.2f", node.snr))dB") + .foregroundColor(getSnrColor(snr: node.snr, preset: modemPreset)) + .font(.caption) + Text("RSSI \(node.rssi)dB") + .foregroundColor(getRssiColor(rssi: node.rssi)) + .font(.caption) + } + } + if node.telemetries?.count ?? 0 > 0 { + Spacer() + BatteryGauge(node: node) + } + Spacer() + } + .listRowSeparator(.hidden) if let user = node.user { if !user.keyMatch { Label { @@ -406,6 +438,17 @@ struct NodeDetail: View { } } .listStyle(.insetGrouped) + .onFirstAppear { + Api().loadDeviceHardwareData { (hw) in + for device in hw { + let currentHardware = node.user?.hwModel ?? "UNSET" + let deviceString = device.hwModelSlug.replacingOccurrences(of: "_", with: "") + if deviceString == currentHardware { + currentDevice = device + } + } + } + } } } } diff --git a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift index e0da484e..649fe6d1 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift @@ -12,61 +12,58 @@ import MapKit struct NodeInfoItem: View { @ObservedObject var node: NodeInfoEntity - - var modemPreset: ModemPresets = ModemPresets( - rawValue: UserDefaults.modemPreset - ) ?? ModemPresets.longFast + var supported: Bool var body: some View { + if let user = node.user { ViewThatFits(in: .horizontal) { - VStack { - if let user = node.user { - HStack(alignment: .center) { - if user.hwModel != "UNSET" { - Image(user.hardwareImage ?? "UNSET") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 65, height: 65) - .cornerRadius(5) - Text(String(node.user?.hwDisplayName ?? (node.user?.hwModel ?? "unset".localized))) - .font(.callout) - } else { - Image(systemName: "person.crop.circle.badge.questionmark") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 65, height: 65) - .cornerRadius(5) - Text(String("incomplete".localized)) + HStack { + Spacer() + VStack(alignment: .center) { + Spacer() + Image(systemName: supported ? "checkmark.seal.fill" : "x.circle") + .resizable() + .aspectRatio(contentMode: .fill) // << here !! + .frame(width: 75, height: 75) + .foregroundStyle(supported ? .green : .red) + Text( supported ? "Supported" : "Unsupported") + .foregroundStyle(.gray) .font(.callout) + } + Spacer() + VStack(alignment: .center) { + HStack { + if user.hwModel != "UNSET" { + Image(user.hardwareImage ?? "UNSET") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxHeight: 150) + .cornerRadius(5) + } else { + Image(systemName: "person.crop.circle.badge.questionmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 65, height: 65) + .cornerRadius(5) + } } } + Spacer() } - HStack(alignment: .center) { - Spacer() - CircleText( - text: node.user?.shortName ?? "?", - color: Color(UIColor(hex: UInt32(node.num))), - circleSize: 75 - ) - if node.snr != 0 && !node.viaMqtt && node.hopsAway == 0 { - Spacer() - VStack { - let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: modemPreset) - LoRaSignalStrengthIndicator(signalStrength: signalStrength) - Text("Signal \(signalStrength.description)").font(.footnote) - Text("SNR \(String(format: "%.2f", node.snr))dB") - .foregroundColor(getSnrColor(snr: node.snr, preset: modemPreset)) - .font(.caption) - Text("RSSI \(node.rssi)dB") - .foregroundColor(getRssiColor(rssi: node.rssi)) - .font(.caption) - } - } - if node.telemetries?.count ?? 0 > 0 { - Spacer() - BatteryGauge(node: node) - } - Spacer() + } + .listRowSeparator(.hidden) + HStack { + Label { + Text("Model") + } icon: { + Image(systemName: "flipphone") + .symbolRenderingMode(.hierarchical) + } + Spacer() + if user.hwModel != "UNSET" { + Text(String(node.user?.hwDisplayName ?? (node.user?.hwModel ?? "unset".localized))) + } else { + Text(String("incomplete".localized)) } } } diff --git a/Meshtastic/Views/Settings/Firmware.swift b/Meshtastic/Views/Settings/Firmware.swift index 9962e69d..6e1427bf 100644 --- a/Meshtastic/Views/Settings/Firmware.swift +++ b/Meshtastic/Views/Settings/Firmware.swift @@ -185,7 +185,7 @@ struct Firmware: View { } .padding() .padding(.bottom, 5) - .onAppear { + .onFirstAppear { Api().loadDeviceHardwareData { (hw) in for device in hw { let currentHardware = node?.user?.hwModel ?? "UNSET"