mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Clean up channel qr code functionality.
This commit is contained in:
parent
0fcf4fdbcb
commit
b4c749a978
5 changed files with 94 additions and 70 deletions
|
|
@ -36770,7 +36770,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"These settings will %@" : {
|
||||
"comment" : "A paragraph below the title that explains what the user is about to do.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"These settings will %@ channels. The current LoRa Config will be replaced, if there are substantial changes to the LoRa config the device will reboot" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
|
|
|
|||
|
|
@ -509,32 +509,32 @@ extension AccessoryManager {
|
|||
let logString = String.localizedStringWithFormat("Sent a Channel for: %@ Channel Index %d".localized, String(deviceNum), chan.index)
|
||||
try await send(toRadio, debugDescription: logString)
|
||||
}
|
||||
|
||||
// Save the LoRa Config and the device will reboot
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.setConfig.lora = channelSet.loraConfig
|
||||
adminPacket.setConfig.lora.configOkToMqtt = okToMQTT // Preserve users okToMQTT choice
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(deviceNum)
|
||||
meshPacket.from = UInt32(deviceNum)
|
||||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = true
|
||||
meshPacket.channel = 0
|
||||
var dataMessage = DataMessage()
|
||||
guard let adminData: Data = try? adminPacket.serializedData() else {
|
||||
throw AccessoryError.ioFailed("sendReboot: Unable to serialize Admin packet")
|
||||
if !addChannels {
|
||||
// Save the LoRa Config and the device will reboot
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.setConfig.lora = channelSet.loraConfig
|
||||
adminPacket.setConfig.lora.configOkToMqtt = okToMQTT // Preserve users okToMQTT choice
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(deviceNum)
|
||||
meshPacket.from = UInt32(deviceNum)
|
||||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = true
|
||||
meshPacket.channel = 0
|
||||
var dataMessage = DataMessage()
|
||||
guard let adminData: Data = try? adminPacket.serializedData() else {
|
||||
throw AccessoryError.ioFailed("sendReboot: Unable to serialize Admin packet")
|
||||
}
|
||||
dataMessage.payload = adminData
|
||||
dataMessage.portnum = PortNum.adminApp
|
||||
meshPacket.decoded = dataMessage
|
||||
var toRadio: ToRadio!
|
||||
toRadio = ToRadio()
|
||||
toRadio.packet = meshPacket
|
||||
|
||||
let logString = String.localizedStringWithFormat("Sent a LoRa.Config for: %@".localized, String(deviceNum))
|
||||
try await send(toRadio, debugDescription: logString)
|
||||
}
|
||||
dataMessage.payload = adminData
|
||||
dataMessage.portnum = PortNum.adminApp
|
||||
meshPacket.decoded = dataMessage
|
||||
var toRadio: ToRadio!
|
||||
toRadio = ToRadio()
|
||||
toRadio.packet = meshPacket
|
||||
|
||||
let logString = String.localizedStringWithFormat("Sent a LoRa.Config for: %@".localized, String(deviceNum))
|
||||
try await send(toRadio, debugDescription: logString)
|
||||
|
||||
Logger.transport.debug("[AccessoryManager] sending wantConfig for saveChannelSet")
|
||||
try await sendWantConfig()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,18 @@ extension URL {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
var queryParameters: [String: String]? {
|
||||
guard let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
|
||||
let queryItems = components.queryItems else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var parameters = [String: String]()
|
||||
for item in queryItems {
|
||||
parameters[item.name] = item.value
|
||||
}
|
||||
return parameters
|
||||
}
|
||||
var attributes: [FileAttributeKey: Any]? {
|
||||
do {
|
||||
return try FileManager.default.attributesOfItem(atPath: path)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import DatadogRUM
|
|||
import DatadogTrace
|
||||
import DatadogLogs
|
||||
import DatadogSessionReplay
|
||||
|
||||
@main
|
||||
struct MeshtasticAppleApp: App {
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ struct MeshtasticAppleApp: App {
|
|||
Logs.enable()
|
||||
Trace.enable(
|
||||
with: Trace.Configuration(
|
||||
sampleRate: 100, networkInfoEnabled: true // 100% sampling for development/testing, reduce for production
|
||||
sampleRate: 100, networkInfoEnabled: true // 100% sampling for development/testing, reduce for production
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -96,14 +97,45 @@ struct MeshtasticAppleApp: App {
|
|||
#endif
|
||||
if !UserDefaults.firstLaunch {
|
||||
// If this is first launch, we will show onboarding screens which
|
||||
// Step through the authorization process. Do not start discovery
|
||||
// Step through the authorization process. Do not start discovery
|
||||
// unitl this workflow completes, otherwise the discovery process
|
||||
// may trigger permission dialogs too soon.
|
||||
accessoryManager.startDiscovery()
|
||||
}
|
||||
}
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
|
||||
private func handleChannelLinkURL(_ url: URL, fromActivity: Bool) {
|
||||
// Reset the state before processing a new URL
|
||||
self.saveChannelLink = nil
|
||||
|
||||
guard url.absoluteString.lowercased().contains("meshtastic.org/e/") else {
|
||||
return
|
||||
}
|
||||
|
||||
let queryParams = url.queryParameters
|
||||
let addChannels = Bool(queryParams?["add"] ?? "false") ?? false
|
||||
var channelData: String?
|
||||
let urlString = url.absoluteString
|
||||
|
||||
if let fragment = urlString.components(separatedBy: "#").last, !fragment.isEmpty {
|
||||
channelData = fragment.components(separatedBy: "?").first
|
||||
}
|
||||
|
||||
guard let finalChannelData = channelData, !finalChannelData.isEmpty else {
|
||||
Logger.mesh.error("Could not extract channel data from URL: \(url.absoluteString, privacy: .public)")
|
||||
return
|
||||
}
|
||||
|
||||
self.saveChannelLink = SaveChannelLinkData(data: finalChannelData, add: addChannels)
|
||||
Logger.services.debug("Add Channel \(addChannels, privacy: .public) with data: \(finalChannelData, privacy: .public)")
|
||||
|
||||
// Log based on the calling context
|
||||
let source = fromActivity ? "User Activity" : "Open URL"
|
||||
Logger.mesh.debug("User wants to open a Channel Settings URL (\(source)): \(url.absoluteString, privacy: .public)")
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView(
|
||||
appState: appState,
|
||||
router: appState.router
|
||||
|
|
@ -112,7 +144,7 @@ struct MeshtasticAppleApp: App {
|
|||
) { link in
|
||||
SaveChannelQRCode(
|
||||
channelSetLink: link.data,
|
||||
addChannels: link.add,
|
||||
addChannels: link.add, // <-- Uses the now reliable 'add' boolean
|
||||
accessoryManager: accessoryManager )
|
||||
.presentationDetents([.large])
|
||||
.presentationDragIndicator(.visible)
|
||||
|
|
@ -121,27 +153,16 @@ struct MeshtasticAppleApp: App {
|
|||
Logger.mesh.debug("URL received \(userActivity, privacy: .public)")
|
||||
self.incomingUrl = userActivity.webpageURL
|
||||
self.saveChannelLink = nil
|
||||
var addChannels = false
|
||||
if self.incomingUrl?.absoluteString.lowercased().contains("meshtastic.org/v/#") == true {
|
||||
ContactURLHandler.handleContactUrl(url: self.incomingUrl!, accessoryManager: accessoryManager)
|
||||
} else if self.incomingUrl?.absoluteString.lowercased().contains("meshtastic.org/e/") == true {
|
||||
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
|
||||
addChannels = Bool(self.incomingUrl?["add"] ?? "false") ?? false
|
||||
if (self.incomingUrl?.absoluteString.lowercased().contains("?")) != nil {
|
||||
guard let cs = components.last!.components(separatedBy: "?").first else {
|
||||
return
|
||||
}
|
||||
self.saveChannelLink = SaveChannelLinkData(data: cs, add: addChannels)
|
||||
} else {
|
||||
guard let cs = components.first else {
|
||||
return
|
||||
}
|
||||
self.saveChannelLink = SaveChannelLinkData(data: cs, add: addChannels)
|
||||
}
|
||||
Logger.services.debug("Add Channel \(addChannels, privacy: .public)")
|
||||
|
||||
if let url = userActivity.webpageURL {
|
||||
if url.absoluteString.lowercased().contains("meshtastic.org/v/#") == true {
|
||||
ContactURLHandler.handleContactUrl(url: url, accessoryManager: accessoryManager)
|
||||
} else if url.absoluteString.lowercased().contains("meshtastic.org/e/") == true {
|
||||
// **Consolidated Call for User Activity**
|
||||
handleChannelLinkURL(url, fromActivity: true)
|
||||
}
|
||||
Logger.mesh.debug("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")")
|
||||
}
|
||||
|
||||
if self.saveChannelLink != nil {
|
||||
Logger.mesh.debug("User wants to open Channel Settings URL: \(String(describing: self.incomingUrl!.relativeString), privacy: .public)")
|
||||
}
|
||||
|
|
@ -149,26 +170,12 @@ struct MeshtasticAppleApp: App {
|
|||
.onOpenURL(perform: { (url) in
|
||||
Logger.mesh.debug("Some sort of URL was received \(url, privacy: .public)")
|
||||
self.incomingUrl = url
|
||||
var addChannels = false
|
||||
|
||||
if url.absoluteString.lowercased().contains("meshtastic.org/v/#") {
|
||||
ContactURLHandler.handleContactUrl(url: url, accessoryManager: accessoryManager)
|
||||
} else if url.absoluteString.lowercased().contains("meshtastic.org/e/") {
|
||||
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
|
||||
addChannels = Bool(self.incomingUrl?["add"] ?? "false") ?? false
|
||||
if self.incomingUrl?.absoluteString.lowercased().contains("?") != nil {
|
||||
guard let cs = components.last!.components(separatedBy: "?").first else {
|
||||
return
|
||||
}
|
||||
self.saveChannelLink = SaveChannelLinkData(data: cs, add: addChannels)
|
||||
} else {
|
||||
guard let cs = components.first else {
|
||||
return
|
||||
}
|
||||
self.saveChannelLink = SaveChannelLinkData(data: cs, add: addChannels)
|
||||
}
|
||||
Logger.services.debug("Add Channel \(addChannels, privacy: .public)")
|
||||
}
|
||||
Logger.mesh.debug("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link", privacy: .public)")
|
||||
// **Consolidated Call for Open URL**
|
||||
handleChannelLinkURL(url, fromActivity: false)
|
||||
} else if url.absoluteString.lowercased().contains("meshtastic:///") {
|
||||
appState.router.route(url: url)
|
||||
}
|
||||
|
|
@ -183,7 +190,7 @@ struct MeshtasticAppleApp: App {
|
|||
.displayFrequency(.immediate)
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: scenePhase) { (_, newScenePhase) in
|
||||
switch newScenePhase {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct SaveChannelQRCode: View {
|
|||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.managedObjectContext) var context
|
||||
let channelSetLink: String
|
||||
var addChannels: Bool = false
|
||||
@State var addChannels: Bool = false
|
||||
var accessoryManager: AccessoryManager
|
||||
|
||||
@State private var showError: Bool = false
|
||||
|
|
@ -31,13 +31,13 @@ struct SaveChannelQRCode: View {
|
|||
VStack {
|
||||
Text("\(addChannels ? "Add" : "Replace all") Channels?")
|
||||
.font(.title)
|
||||
Text("These settings will \(addChannels ? "add" : "replace all") channels. The current LoRa Config will be replaced, if there are substantial changes to the LoRa config the device will reboot")
|
||||
Text("These settings will \(addChannels ? "add channels without changing any LoRa config values." : "replace all channels. The current LoRa Config will be replaced, if there are substantial changes to the LoRa config the device will reboot automatically.")")
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.foregroundColor(.gray)
|
||||
.font(.title3)
|
||||
.padding()
|
||||
|
||||
if !loraChanges.isEmpty {
|
||||
if !loraChanges.isEmpty && !addChannels {
|
||||
VStack(alignment: .leading) {
|
||||
Text("LoRa Config Changes:")
|
||||
.font(.headline)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue