mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Fixing linting errors caused by the bens
This commit is contained in:
parent
dde0ea080f
commit
2b0ce47f22
17 changed files with 54 additions and 130 deletions
|
|
@ -1295,7 +1295,7 @@
|
|||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1540;
|
||||
LastUpgradeCheck = 1630;
|
||||
LastUpgradeCheck = 1640;
|
||||
TargetAttributes = {
|
||||
25F5D5C62C4375A8008036E3 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
|
|
@ -1713,6 +1713,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
|
|
@ -1778,6 +1779,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1630"
|
||||
LastUpgradeVersion = "1640"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1630"
|
||||
LastUpgradeVersion = "1640"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
|
|
@ -11,10 +11,8 @@ import AppIntents
|
|||
struct FactoryResetNodeIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Factory Reset"
|
||||
static var description: IntentDescription = "Perform a factory reset on the node you are connected to"
|
||||
|
||||
@Parameter(title: "Hard Reset", description: "In addition to Config, Keys and BLE bonds will be wiped", default: false)
|
||||
var hardReset: Bool
|
||||
|
||||
@Parameter(title: "Provide Confirmation", description: "Show a confirmation dialog before performing the factory reset", default: true)
|
||||
var provideConfirmation: Bool
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ struct RestartNodeIntent: AppIntent {
|
|||
|
||||
func perform() async throws -> some IntentResult {
|
||||
|
||||
|
||||
if !BLEManager.shared.isConnected {
|
||||
throw AppIntentErrors.AppIntentError.notConnected
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import AppIntents
|
|||
import MeshtasticProtobufs
|
||||
|
||||
struct SendWaypointIntent: AppIntent {
|
||||
|
||||
|
||||
var defaultDate = Date.now.addingTimeInterval(60 * 480)
|
||||
|
||||
static var title = LocalizedStringResource("Send a Waypoint")
|
||||
|
|
@ -83,11 +83,9 @@ struct SendWaypointIntent: AppIntent {
|
|||
newWaypoint.icon = unicode
|
||||
newWaypoint.name = name
|
||||
newWaypoint.description_p = description
|
||||
|
||||
if let expirationDate = expiration {
|
||||
newWaypoint.expire = UInt32(expirationDate.timeIntervalSince1970)
|
||||
}
|
||||
|
||||
if isLocked {
|
||||
if let connectedPeripheral = BLEManager.shared.connectedPeripheral {
|
||||
newWaypoint.lockedTo = UInt32(connectedPeripheral.num)
|
||||
|
|
|
|||
|
|
@ -158,12 +158,13 @@ extension UserDefaults {
|
|||
|
||||
@UserDefault(.mapReportingOptIn, defaultValue: false)
|
||||
static var mapReportingOptIn: Bool
|
||||
|
||||
|
||||
@UserDefault(.usageDataAndCrashReporting, defaultValue: true)
|
||||
static var usageDataAndCrashReporting: Bool
|
||||
|
||||
@UserDefault(.firstLaunch, defaultValue: true)
|
||||
static var firstLaunch: Bool
|
||||
|
||||
|
||||
@UserDefault(.showDeviceOnboarding, defaultValue: false)
|
||||
static var showDeviceOnboarding: Bool
|
||||
|
||||
|
|
|
|||
|
|
@ -1142,8 +1142,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
sendWantConfig()
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: Share Location Position Update Timer
|
||||
// Use context to pass the radio name with the timer
|
||||
// Use a RunLoop to prevent the timer from running on the main UI thread
|
||||
|
|
@ -1159,7 +1157,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
if decodedInfo.configCompleteID != 0 && decodedInfo.configCompleteID == NONCE_ONLY_DB {
|
||||
Logger.mesh.info("🤜 [BLE] Want Config DB Complete. ID:\(decodedInfo.configCompleteID, privacy: .public)")
|
||||
}
|
||||
|
||||
case FROMNUM_UUID:
|
||||
Logger.services.info("🗞️ [BLE] (Notify) characteristic value will be read next")
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -11,15 +11,11 @@ import TipKit
|
|||
import MeshtasticProtobufs
|
||||
|
||||
struct ContactURLHandler {
|
||||
|
||||
static var minimumContactVersion = "2.6.9"
|
||||
|
||||
|
||||
static func handleContactUrl(url: URL, bleManager: BLEManager) {
|
||||
let supportedVersion = UserDefaults.firmwareVersion == "0.0.0" ||
|
||||
minimumContactVersion.compare(UserDefaults.firmwareVersion, options: .numeric) == .orderedAscending ||
|
||||
minimumContactVersion.compare(UserDefaults.firmwareVersion, options: .numeric) == .orderedSame
|
||||
|
||||
if !supportedVersion {
|
||||
let alertController = UIAlertController(
|
||||
title: "Firmware Upgrade Required",
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ struct MeshtasticAppleApp: App {
|
|||
trackingConsent: UserDefaults.usageDataAndCrashReporting ? .granted : .notGranted,
|
||||
)
|
||||
DatadogCrashReporting.CrashReporting.enable()
|
||||
|
||||
Logs.enable()
|
||||
|
||||
Trace.enable(
|
||||
with: Trace.Configuration(
|
||||
sampleRate: 100, networkInfoEnabled: true // 100% sampling for development/testing, reduce for production
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
case "messageNotification.thumbsUpAction":
|
||||
if let channel = userInfo["channel"] as? Int32,
|
||||
let replyID = userInfo["messageId"] as? Int64 {
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage (
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage(
|
||||
message: Tapbacks.thumbsUp.emojiString,
|
||||
toUserNum: userInfo["userNum"] as? Int64 ?? 0,
|
||||
channel: channel,
|
||||
|
|
@ -64,7 +64,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
case "messageNotification.thumbsDownAction":
|
||||
if let channel = userInfo["channel"] as? Int32,
|
||||
let replyID = userInfo["messageId"] as? Int64 {
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage (
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage(
|
||||
message: Tapbacks.thumbsDown.emojiString,
|
||||
toUserNum: userInfo["userNum"] as? Int64 ?? 0,
|
||||
channel: channel,
|
||||
|
|
@ -79,7 +79,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
if let userInput = (response as? UNTextInputNotificationResponse)?.userText,
|
||||
let channel = userInfo["channel"] as? Int32,
|
||||
let replyID = userInfo["messageId"] as? Int64 {
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage (
|
||||
let tapbackResponse = !BLEManager.shared.sendMessage(
|
||||
message: userInput,
|
||||
toUserNum: userInfo["userNum"] as? Int64 ?? 0,
|
||||
channel: channel,
|
||||
|
|
|
|||
|
|
@ -1369,7 +1369,6 @@ func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nod
|
|||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 [RangeTestConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
|
||||
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
|
|
|
|||
|
|
@ -7,19 +7,18 @@
|
|||
import SwiftUI
|
||||
|
||||
struct ChannelLock: View {
|
||||
|
||||
|
||||
@ObservedObject var channel: ChannelEntity
|
||||
|
||||
var body: some View {
|
||||
/// Unencrypted - using no key at all or a known 1 byte key
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
let preciseLoction = 17...32
|
||||
// Using precise location and have MQTT uplink enabled
|
||||
if channel.uplinkEnabled && preciseLoction ~= (Int(channel.positionPrecision)) {
|
||||
if channel.uplinkEnabled && preciseLoction ~= (Int(channel.positionPrecision)) {
|
||||
Image(systemName: "lock.open.trianglebadge.exclamationmark.fill")
|
||||
.foregroundColor(.red)
|
||||
// Using precise location
|
||||
} else if preciseLoction ~= (Int(channel.positionPrecision)) {
|
||||
} else if preciseLoction ~= (Int(channel.positionPrecision)) {
|
||||
Image(systemName: "lock.open.fill")
|
||||
.foregroundColor(.red)
|
||||
// Just unencrypted without any location or MQTT
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ struct MessageText: View {
|
|||
locale: Locale.current
|
||||
)
|
||||
static let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mm:ss:a")
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
|
||||
let message: MessageEntity
|
||||
let tapBackDestination: MessageDestination
|
||||
let isCurrentUser: Bool
|
||||
|
|
@ -21,7 +19,6 @@ struct MessageText: View {
|
|||
@State private var saveChannels = false
|
||||
@State private var channelSettings: String?
|
||||
@State private var addChannels = false
|
||||
|
||||
@State private var isShowingDeleteConfirmation = false
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -41,10 +38,10 @@ struct MessageText: View {
|
|||
HStack {
|
||||
Spacer()
|
||||
Image(systemName: "lock.circle.fill")
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, .green)
|
||||
.font(.system(size: 20))
|
||||
.offset(x: 8, y: 8)
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, .green)
|
||||
.font(.system(size: 20))
|
||||
.offset(x: 8, y: 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,10 +53,10 @@ struct MessageText: View {
|
|||
HStack {
|
||||
Spacer()
|
||||
Image(systemName: "envelope.circle.fill")
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, .gray)
|
||||
.font(.system(size: 20))
|
||||
.offset(x: 8, y: 8)
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, .gray)
|
||||
.font(.system(size: 20))
|
||||
.offset(x: 8, y: 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -89,39 +86,32 @@ struct MessageText: View {
|
|||
}
|
||||
.environment(\.openURL, OpenURLAction { url in
|
||||
channelSettings = nil
|
||||
|
||||
if url.absoluteString.lowercased().contains("meshtastic.org/v/#") {
|
||||
// Handle contact URL
|
||||
ContactURLHandler.handleContactUrl(url: url, bleManager: BLEManager.shared)
|
||||
return .handled // Prevent default browser opening
|
||||
} else if url.absoluteString.lowercased().contains("meshtastic.org/e/") {
|
||||
// Handle channel URL
|
||||
let components = url.absoluteString.components(separatedBy: "#")
|
||||
guard !components.isEmpty, let lastComponent = components.last else {
|
||||
Logger.services.error("No valid components found in channel URL: \(url.absoluteString, privacy: .public)")
|
||||
return .discarded
|
||||
}
|
||||
|
||||
self.addChannels = Bool(url.query?.contains("add=true") ?? false)
|
||||
guard let lastComponent = components.last else {
|
||||
Logger.services.error("Channel URL missing fragment component: \(url.absoluteString, privacy: .public)")
|
||||
self.channelSettings = nil
|
||||
return .discarded
|
||||
}
|
||||
|
||||
self.channelSettings = lastComponent.components(separatedBy: "?").first ?? ""
|
||||
|
||||
|
||||
Logger.services.debug("Add Channel: \(self.addChannels, privacy: .public)")
|
||||
self.saveChannels = true
|
||||
Logger.mesh.debug("Opening Channel Settings URL: \(url.absoluteString, privacy: .public)")
|
||||
return .handled // Prevent default browser opening
|
||||
}
|
||||
|
||||
return .systemAction // Open other URLs in browser
|
||||
})
|
||||
|
||||
// Display sheet for channel settings
|
||||
if url.absoluteString.lowercased().contains("meshtastic.org/v/#") {
|
||||
// Handle contact URL
|
||||
ContactURLHandler.handleContactUrl(url: url, bleManager: BLEManager.shared)
|
||||
return .handled // Prevent default browser opening
|
||||
} else if url.absoluteString.lowercased().contains("meshtastic.org/e/") {
|
||||
// Handle channel URL
|
||||
let components = url.absoluteString.components(separatedBy: "#")
|
||||
guard !components.isEmpty, let lastComponent = components.last else {
|
||||
Logger.services.error("No valid components found in channel URL: \(url.absoluteString, privacy: .public)")
|
||||
return .discarded
|
||||
}
|
||||
self.addChannels = Bool(url.query?.contains("add=true") ?? false)
|
||||
guard let lastComponent = components.last else {
|
||||
Logger.services.error("Channel URL missing fragment component: \(url.absoluteString, privacy: .public)")
|
||||
self.channelSettings = nil
|
||||
return .discarded
|
||||
}
|
||||
self.channelSettings = lastComponent.components(separatedBy: "?").first ?? ""
|
||||
Logger.services.debug("Add Channel: \(self.addChannels, privacy: .public)")
|
||||
self.saveChannels = true
|
||||
Logger.mesh.debug("Opening Channel Settings URL: \(url.absoluteString, privacy: .public)")
|
||||
return .handled // Prevent default browser opening
|
||||
}
|
||||
return .systemAction // Open other URLs in browser
|
||||
})
|
||||
// Display sheet for channel settings
|
||||
.sheet(isPresented: Binding(
|
||||
get: {
|
||||
saveChannels && !(channelSettings == nil)
|
||||
|
|
|
|||
|
|
@ -19,22 +19,17 @@ struct NodeDetail: View {
|
|||
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
|
||||
|
||||
// The node the device is currently connected to
|
||||
var connectedNode: NodeInfoEntity?
|
||||
|
||||
// The node information being displayed on the detail screen
|
||||
@ObservedObject
|
||||
var node: NodeInfoEntity
|
||||
|
||||
var columnVisibility = NavigationSplitViewVisibility.all
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
|
|
@ -42,7 +37,6 @@ struct NodeDetail: View {
|
|||
id: bleManager.connectedPeripheral?.num ?? -1,
|
||||
context: context
|
||||
)
|
||||
|
||||
Section("Hardware") {
|
||||
NodeInfoItem(node: node)
|
||||
}
|
||||
|
|
@ -106,10 +100,9 @@ struct NodeDetail: View {
|
|||
}
|
||||
Spacer()
|
||||
Text(String(node.num))
|
||||
.textSelection(.enabled)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
|
||||
HStack {
|
||||
Label {
|
||||
Text("User Id")
|
||||
|
|
@ -119,10 +112,9 @@ struct NodeDetail: View {
|
|||
}
|
||||
Spacer()
|
||||
Text(node.num.toHex())
|
||||
.textSelection(.enabled)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
|
||||
if node.user?.keyMatch ?? false {
|
||||
if let publicKey = node.user?.publicKey {
|
||||
HStack {
|
||||
|
|
@ -134,7 +126,7 @@ struct NodeDetail: View {
|
|||
}
|
||||
Spacer()
|
||||
Button(action: {
|
||||
context.perform{
|
||||
context.perform {
|
||||
UIPasteboard.general.string = publicKey.base64EncodedString()
|
||||
}
|
||||
}) {
|
||||
|
|
@ -147,7 +139,6 @@ struct NodeDetail: View {
|
|||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
}
|
||||
|
||||
if let metadata = node.metadata {
|
||||
HStack {
|
||||
Label {
|
||||
|
|
@ -157,12 +148,10 @@ struct NodeDetail: View {
|
|||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
Text(metadata.firmwareVersion ?? "Unknown".localized)
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
|
||||
if let role = node.user?.role, let deviceRole = DeviceRoles(rawValue: Int(role)) {
|
||||
HStack {
|
||||
Label {
|
||||
|
|
@ -189,7 +178,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
|
||||
if let dm = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")).lastObject as? TelemetryEntity, let uptimeSeconds = dm.uptimeSeconds {
|
||||
HStack {
|
||||
Label {
|
||||
|
|
@ -200,7 +188,6 @@ struct NodeDetail: View {
|
|||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
let now = Date.now
|
||||
let later = now + TimeInterval(uptimeSeconds)
|
||||
let uptime = (now..<later).formatted(.components(style: .narrow))
|
||||
|
|
@ -209,7 +196,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
|
||||
if let firstHeard = node.firstHeard, firstHeard.timeIntervalSince1970 > 0 && firstHeard < Calendar.current.date(byAdding: .year, value: 1, to: Date())! {
|
||||
HStack {
|
||||
Label {
|
||||
|
|
@ -232,7 +218,6 @@ struct NodeDetail: View {
|
|||
dateFormatRelative.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
if let lastHeard = node.lastHeard, lastHeard.timeIntervalSince1970 > 0 && lastHeard < Calendar.current.date(byAdding: .year, value: 1, to: Date())! {
|
||||
HStack {
|
||||
Label {
|
||||
|
|
@ -242,7 +227,6 @@ struct NodeDetail: View {
|
|||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
if dateFormatRelative, let text = Self.relativeFormatter.string(for: lastHeard) {
|
||||
if lastHeard.formatted() != "Unknown Age".localized {
|
||||
Text(text)
|
||||
|
|
@ -259,7 +243,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note, as you add widgets, you should add to the `hasDataForLatestPositions` array
|
||||
// This will make sure the "Environment" section is only displayed when the node has a position
|
||||
// to use with WeatherKit, or has actual data in the most recent EnvironmentMetrics entity
|
||||
|
|
@ -298,7 +281,7 @@ struct NodeDetail: View {
|
|||
let windGust = node.latestEnvironmentMetrics?.windGust.map { Measurement(value: Double($0), unit: UnitSpeed.metersPerSecond) }
|
||||
let direction = cardinalValue(from: Double(node.latestEnvironmentMetrics?.windDirection ?? 0))
|
||||
WindCompactWidget(speed: windSpeedMeasurement.formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))),
|
||||
gust: node.latestEnvironmentMetrics?.windGust ?? 0.0 > 0.0 ? windGust?.formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))) : "", direction: direction)
|
||||
gust: node.latestEnvironmentMetrics?.windGust ?? 0.0 > 0.0 ? windGust?.formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))) : "", direction: direction)
|
||||
}
|
||||
if let rainfall1h = node.latestEnvironmentMetrics?.rainfall1H {
|
||||
let locale = NSLocale.current as NSLocale
|
||||
|
|
@ -370,7 +353,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasDeviceMetrics)
|
||||
|
||||
NavigationLink {
|
||||
NodeMapSwiftUI(node: node, showUserLocation: connectedNode?.num ?? 0 == node.num)
|
||||
} label: {
|
||||
|
|
@ -382,7 +364,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasPositions)
|
||||
|
||||
NavigationLink {
|
||||
PositionLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -394,7 +375,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasPositions)
|
||||
|
||||
NavigationLink {
|
||||
EnvironmentMetricsLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -406,7 +386,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasEnvironmentMetrics)
|
||||
|
||||
NavigationLink {
|
||||
TraceRouteLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -418,7 +397,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(node.traceRoutes?.count ?? 0 == 0)
|
||||
|
||||
NavigationLink {
|
||||
PowerMetricsLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -430,7 +408,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasPowerMetrics)
|
||||
|
||||
NavigationLink {
|
||||
DetectionSensorLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -442,7 +419,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.disabled(!node.hasDetectionSensorMetrics)
|
||||
|
||||
if node.hasPax {
|
||||
NavigationLink {
|
||||
PaxCounterLog(node: node)
|
||||
|
|
@ -457,7 +433,6 @@ struct NodeDetail: View {
|
|||
.disabled(!node.hasPax)
|
||||
}
|
||||
}
|
||||
|
||||
Section("Actions") {
|
||||
if let user = node.user {
|
||||
NodeAlertsButton(
|
||||
|
|
@ -466,7 +441,6 @@ struct NodeDetail: View {
|
|||
user: user
|
||||
)
|
||||
}
|
||||
|
||||
if let connectedNode {
|
||||
FavoriteNodeButton(
|
||||
bleManager: bleManager,
|
||||
|
|
@ -491,7 +465,7 @@ struct NodeDetail: View {
|
|||
}
|
||||
if node.hasPositions {
|
||||
NavigateToButton(node: node)
|
||||
}
|
||||
}
|
||||
IgnoreNodeButton(
|
||||
bleManager: bleManager,
|
||||
context: context,
|
||||
|
|
@ -506,7 +480,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let metadata = node.metadata,
|
||||
let connectedNode,
|
||||
self.bleManager.connectedPeripheral != nil {
|
||||
|
|
@ -529,7 +502,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if metadata.canShutdown {
|
||||
Button {
|
||||
showingShutdownConfirm = true
|
||||
|
|
@ -549,7 +521,6 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
showingRebootConfirm = true
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -241,7 +241,6 @@ struct Channels: View {
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if node?.myInfo?.channels?.array.count ?? 0 < 8 && node != nil {
|
||||
|
||||
Button {
|
||||
|
|
|
|||
|
|
@ -12,18 +12,14 @@ import MeshtasticProtobufs
|
|||
struct SaveChannelQRCode: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.managedObjectContext) var context
|
||||
|
||||
let channelSetLink: String
|
||||
var addChannels: Bool = false
|
||||
var bleManager: BLEManager
|
||||
|
||||
@State private var showError: Bool = false
|
||||
@State private var errorMessage: String = ""
|
||||
@State private var connectedToDevice: Bool = false
|
||||
@State private var loraChanges: [String] = []
|
||||
@State private var okToMQTT: Bool = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("\(addChannels ? "Add" : "Replace all") Channels?")
|
||||
|
|
@ -47,7 +43,6 @@ struct SaveChannelQRCode: View {
|
|||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
if showError {
|
||||
Text(errorMessage.isEmpty ? "Channels being added from the QR code did not save. When adding channels the names must be unique." : errorMessage)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
|
@ -55,7 +50,6 @@ struct SaveChannelQRCode: View {
|
|||
.font(.callout)
|
||||
.padding()
|
||||
}
|
||||
|
||||
HStack {
|
||||
if !showError {
|
||||
Button {
|
||||
|
|
@ -72,7 +66,6 @@ struct SaveChannelQRCode: View {
|
|||
} else {
|
||||
channelData = channelSetLink
|
||||
}
|
||||
|
||||
let success = bleManager.saveChannelSet(base64UrlString: channelData, addChannels: addChannels, okToMQTT: okToMQTT)
|
||||
if success {
|
||||
dismiss()
|
||||
|
|
@ -119,11 +112,8 @@ struct SaveChannelQRCode: View {
|
|||
fetchLoRaConfigChanges()
|
||||
}
|
||||
}
|
||||
|
||||
private func extractChannelDataFromURL(_ urlString: String) -> String? {
|
||||
Logger.data.info("Extracting channel data from URL: \(urlString)")
|
||||
|
||||
|
||||
if let url = URL(string: urlString) {
|
||||
// Get the fragment (part after #)
|
||||
if let fragment = url.fragment, !fragment.isEmpty {
|
||||
|
|
@ -131,7 +121,6 @@ struct SaveChannelQRCode: View {
|
|||
return fragment
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: manually extract everything after the last #
|
||||
if let hashIndex = urlString.lastIndex(of: "#") {
|
||||
let startIndex = urlString.index(after: hashIndex)
|
||||
|
|
@ -141,11 +130,9 @@ struct SaveChannelQRCode: View {
|
|||
return channelData
|
||||
}
|
||||
}
|
||||
|
||||
Logger.data.error("Failed to extract channel data from URL: \(urlString)")
|
||||
return nil
|
||||
}
|
||||
|
||||
private func fetchLoRaConfigChanges() {
|
||||
var currentLoRaConfig: Config.LoRaConfig?
|
||||
|
||||
|
|
@ -163,13 +150,10 @@ struct SaveChannelQRCode: View {
|
|||
// Assume it's already the base64 data
|
||||
channelData = channelSetLink
|
||||
}
|
||||
|
||||
Logger.data.info("Processing channel data: \(channelData)")
|
||||
|
||||
// Fetch current LoRa config from Core Data
|
||||
let fetchRequest = NodeInfoEntity.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(format: "num == %lld", Int64(bleManager.connectedPeripheral?.num ?? 0))
|
||||
|
||||
do {
|
||||
let nodes = try context.fetch(fetchRequest)
|
||||
if let node = nodes.first {
|
||||
|
|
@ -178,7 +162,6 @@ struct SaveChannelQRCode: View {
|
|||
} catch {
|
||||
Logger.data.error("Failed to fetch NodeInfoEntity: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
|
||||
// Decode base64url string
|
||||
let decodedString = channelData.base64urlToBase64()
|
||||
guard let decodedData = Data(base64Encoded: decodedString) else {
|
||||
|
|
@ -187,7 +170,6 @@ struct SaveChannelQRCode: View {
|
|||
showError = true
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let channelSet = try ChannelSet(serializedBytes: decodedData)
|
||||
let newLoRaConfig = channelSet.loraConfig
|
||||
|
|
@ -244,7 +226,6 @@ struct SaveChannelQRCode: View {
|
|||
} else {
|
||||
// Compare against default values when no current config exists
|
||||
let defaultConfig = getDefaultLoRaConfig()
|
||||
|
||||
if newLoRaConfig.hopLimit != defaultConfig.hopLimit {
|
||||
changes.append("Hop Limit: \(defaultConfig.hopLimit) -> \(newLoRaConfig.hopLimit)")
|
||||
}
|
||||
|
|
@ -287,16 +268,13 @@ struct SaveChannelQRCode: View {
|
|||
changes.append("Ignore MQTT: \(defaultConfig.ignoreMqtt) -> \(newLoRaConfig.ignoreMqtt)")
|
||||
}
|
||||
}
|
||||
|
||||
loraChanges = changes
|
||||
|
||||
} catch {
|
||||
Logger.data.error("Failed to decode ChannelSet: \(error.localizedDescription, privacy: .public)")
|
||||
errorMessage = "Failed to decode channel configuration"
|
||||
showError = true
|
||||
}
|
||||
}
|
||||
|
||||
private func getDefaultLoRaConfig() -> Config.LoRaConfig {
|
||||
var config = Config.LoRaConfig()
|
||||
config.hopLimit = 3
|
||||
|
|
@ -316,7 +294,6 @@ struct SaveChannelQRCode: View {
|
|||
return config
|
||||
}
|
||||
}
|
||||
|
||||
extension LoRaConfigEntity {
|
||||
func toProto() -> Config.LoRaConfig {
|
||||
var config = Config.LoRaConfig()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue