2022-09-27 08:09:35 -07:00
|
|
|
//
|
|
|
|
|
// ShareChannel.swift
|
|
|
|
|
// MeshtasticApple
|
|
|
|
|
//
|
2022-10-14 22:18:28 -07:00
|
|
|
// Copyright(c) Garth Vander Houwen 4/8/22.
|
2022-09-27 08:09:35 -07:00
|
|
|
//
|
|
|
|
|
import SwiftUI
|
|
|
|
|
import CoreData
|
|
|
|
|
import CoreImage.CIFilterBuiltins
|
2024-06-07 22:09:20 -05:00
|
|
|
import MeshtasticProtobufs
|
2023-08-31 22:39:51 -07:00
|
|
|
import TipKit
|
2022-09-27 08:09:35 -07:00
|
|
|
|
|
|
|
|
struct QrCodeImage {
|
|
|
|
|
let context = CIContext()
|
2023-03-06 10:33:18 -08:00
|
|
|
|
2022-09-27 08:09:35 -07:00
|
|
|
func generateQRCode(from text: String) -> UIImage {
|
|
|
|
|
var qrImage = UIImage(systemName: "xmark.circle") ?? UIImage()
|
|
|
|
|
let data = Data(text.utf8)
|
|
|
|
|
let filter = CIFilter.qrCodeGenerator()
|
|
|
|
|
filter.setValue(data, forKey: "inputMessage")
|
2023-03-06 10:33:18 -08:00
|
|
|
|
2022-09-27 08:09:35 -07:00
|
|
|
let transform = CGAffineTransform(scaleX: 20, y: 20)
|
|
|
|
|
if let outputImage = filter.outputImage?.transformed(by: transform) {
|
|
|
|
|
if let image = context.createCGImage(
|
|
|
|
|
outputImage,
|
|
|
|
|
from: outputImage.extent) {
|
|
|
|
|
qrImage = UIImage(cgImage: image)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return qrImage
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-10 13:40:18 -07:00
|
|
|
|
2022-09-27 08:09:35 -07:00
|
|
|
struct ShareChannels: View {
|
2023-03-06 10:33:18 -08:00
|
|
|
|
2022-09-27 08:09:35 -07:00
|
|
|
@Environment(\.managedObjectContext) var context
|
Transports Interface to Support TCP for all Platforms and Serial on Mac (#1341)
* Initial implementation of transports
* Initial LogRadio implementation
* Fixes for Settings view (caused by debug commenting)
* Refinement of the object and actor model
* Connect view text and tab updates
* Fix mac catalyst and tests
* Warning and logging clean-up
* In progress commit
* Serial Transport and Reconnect draft work
* Serial transport and reconnection draft work
* Quick fix for BLE - still more work to do
* interim commit
* More in progress changes
* Minor improvements
* Pretty good initial implementation
* Bump version beyond the app store
* Fix for disconnection swipeAction
* Tweaks to TCPConnection implementation
* Retry for NONCE_ONLY_DB
* Revert json string change
* Simplified some of the API + "Anti-discovery"
* Tweaks for devices leaving the discovery process
* Bump version
* iOS26 Tweaks
* Tweaks and bug fixes
* Add link with slash sf symbol
* update symbol image on connect view
* BLE disconnect handling
* Log privacy attributes
* Onboarding and minor fixes.
* change database to nodes, add emoji to tcp logs
* Error handling improvements
* More logging emojis
* Suppressed unnecessary errors on disconnect
* Heartbeat emoji
* Add bluetooth symbol
* add privacy attributes to [TCP] logs, add custom bluetooth logo
* Improve routing logs
* Emoji for connect logs
* Heartbeat emoji
* Add CBCentralManagerScanOptionAllowDuplicatesKey options to central for bluetooth
* fix nav errors by switching from observableobject to state
* Update connection indicator icon
* fix for BLE disconnects
* Connection process fixes
* More fixes/tweaks to connection process
* Strict concurrency
* Fix some warnings, remove wifi warning
* delete stale keys
* interim commit
* Update privacy for log, fix wrong space
* fix a couple of linting items
* Switch to targeted
* interim commit
* BLE Signal strenth on connect view
* Remove BLE RSSI from long press menu
* Modem lights
* minor spacing tweak
* Additional BLE logging and a scanning fix.
* Discovery and BLE RSSI improvements
* Background suspension
* Update isConnected to enable UI during db load
* update protobufs
* Replace config if statements with switches, Fix unknown module config logging, make dark mode modem circle stroke color white so they are visible
* Additional logging cleanup
* hast
* Set unmessagable to true if the longname has the unmessagable emoji
* Connect error handling improvements
* Admin popup list icon and activity lights updates
* Revert use of .toolbar back to .navigationBarItems
* More public logging
* Better BLE error handling
* Node DB progress meter
* minor tweak to activity light interaction timing
* Fix comment linting, remove stale keys
* Remove stale keys
* Easy linting fixes
* Two more simple linting fixes
* clean up meshtasticapp
* More public logging
* Replay config
* Logging
* Fix for unselected node on Settings
* Tweak to progress meter based on device idiom
* Update protos
* Session replay redaction of messages
* Serial fix for old devices, and a let statement
* Mask text too
* Fix typo
* BLE poweredOff is now an auto-reconnectable error
* Update logging
* Fix for peerRemovedPairingInformation
* Logging for BLE peripheral:didUpdateValueFor errors.
* Fix for inconsistent swipe disconnect behavior
* periperal:didUpdateValueFor error handling
* Fix for BLEConnection continuation guarding
* BLEConnection actor deadlock on disconnect
* Heartbeat nonce
* Fix for swipe disconnect and task cancellation
* Fix for swipe actions not honoring .disabled()
* Tell BLETransport when BLEConnection is cancelled
* Update navigation logging
* Logging updates
* Bump version to 2.7.0
* Organize into folders and heartbeat stuff
* Minor improvements to manual TCP connection
* Auto-connect toggle
* Possible BLE bug, still waiting to see in logs
* Concurrency tweaks
* Concurrency improvements
* requestDeviceMetadata fix. fixes remote admin
* Minor typo fixes
* "All" button for log filters: category and level
* More robust continuation handling for BLE
* @FetchRequest based ChannelMessageList
* Update info.plist and device hardware file
* Move auto connect toggle to app settings and debug mode, tint properly with the accent color
* Add label to auto connect toggle
* Update log for node info received from ourselves over the mesh
* Remove unused scrollViewProxy
* Update Meshtastic/Views/Onboarding/DeviceOnboarding.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update target for connect view
* Properly Set datadog environment
* Comment out ble manager
* Adjust cyclomatic complexity thresholds in .swiftlint.yml
* Linting fixes, delete ble manager
* Make session replay debug only
---------
Co-authored-by: jake-b <jake-b@users.noreply.github.com>
Co-authored-by: jake <jake@jakes-Mac-mini.local>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-27 08:09:02 -07:00
|
|
|
@EnvironmentObject var accessoryManager: AccessoryManager
|
2022-12-09 19:15:15 -08:00
|
|
|
@Environment(\.dismiss) private var dismiss
|
2022-10-10 07:17:57 -07:00
|
|
|
@State var channelSet: ChannelSet = ChannelSet()
|
2022-09-29 22:24:05 -07:00
|
|
|
@State var includeChannel0 = true
|
2022-10-29 07:31:50 -07:00
|
|
|
@State var includeChannel1 = true
|
|
|
|
|
@State var includeChannel2 = true
|
|
|
|
|
@State var includeChannel3 = true
|
|
|
|
|
@State var includeChannel4 = true
|
|
|
|
|
@State var includeChannel5 = true
|
|
|
|
|
@State var includeChannel6 = true
|
|
|
|
|
@State var includeChannel7 = true
|
2024-04-02 23:43:00 -07:00
|
|
|
@State var replaceChannels = true
|
2022-09-27 08:09:35 -07:00
|
|
|
var node: NodeInfoEntity?
|
2022-10-10 14:22:26 -07:00
|
|
|
@State private var channelsUrl = "https://www.meshtastic.org/e/#"
|
2022-09-27 08:09:35 -07:00
|
|
|
var qrCodeImage = QrCodeImage()
|
2025-06-22 20:19:42 -07:00
|
|
|
@State private var showingHelp = false
|
2023-03-06 10:33:18 -08:00
|
|
|
|
2022-09-27 08:09:35 -07:00
|
|
|
var body: some View {
|
2024-05-29 16:40:07 -05:00
|
|
|
|
2024-10-05 10:44:46 -07:00
|
|
|
VStack {
|
|
|
|
|
TipView(ShareChannelsTip(), arrowEdge: .bottom)
|
2025-09-13 14:13:20 -07:00
|
|
|
.tipBackground(Color(.secondarySystemBackground))
|
|
|
|
|
.listRowSeparator(.hidden)
|
2023-09-17 19:42:03 -07:00
|
|
|
}
|
2025-09-13 14:13:20 -07:00
|
|
|
.padding(.horizontal)
|
2022-11-08 12:48:16 -08:00
|
|
|
GeometryReader { bounds in
|
|
|
|
|
let smallest = min(bounds.size.width, bounds.size.height)
|
|
|
|
|
ScrollView {
|
2023-08-31 22:39:51 -07:00
|
|
|
if node != nil && node?.myInfo != nil {
|
|
|
|
|
Grid {
|
|
|
|
|
GridRow {
|
|
|
|
|
Spacer()
|
2025-04-27 11:26:23 -07:00
|
|
|
Text("Include")
|
2023-08-31 22:39:51 -07:00
|
|
|
.font(.caption)
|
|
|
|
|
.fontWeight(.bold)
|
|
|
|
|
.padding(.trailing)
|
2025-02-15 09:40:55 -08:00
|
|
|
Text("Channel")
|
2023-08-31 22:39:51 -07:00
|
|
|
.font(.caption)
|
|
|
|
|
.fontWeight(.bold)
|
|
|
|
|
.padding(.trailing)
|
2025-04-27 11:26:23 -07:00
|
|
|
Text("Encrypted")
|
2023-08-31 22:39:51 -07:00
|
|
|
.font(.caption)
|
|
|
|
|
.fontWeight(.bold)
|
|
|
|
|
}
|
|
|
|
|
ForEach(node?.myInfo?.channels?.array as? [ChannelEntity] ?? [], id: \.self) { (channel: ChannelEntity) in
|
2022-11-08 12:48:16 -08:00
|
|
|
GridRow {
|
|
|
|
|
Spacer()
|
2023-08-31 22:39:51 -07:00
|
|
|
if channel.index == 0 {
|
|
|
|
|
Toggle("Channel 0 Included", isOn: $includeChannel0)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Primary" : channel.name) ?? "Primary").camelCaseToWords())
|
2025-06-22 20:19:42 -07:00
|
|
|
ChannelLock(channel: channel)
|
2023-08-31 22:39:51 -07:00
|
|
|
} else if channel.index == 1 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 1 Included", isOn: $includeChannel1)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 2 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 2 Included", isOn: $includeChannel2)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 3 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 3 Included", isOn: $includeChannel3)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 4 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 4 Included", isOn: $includeChannel4)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 5 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 5 Included", isOn: $includeChannel5)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 6 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 6 Included", isOn: $includeChannel6)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
|
|
|
|
}
|
|
|
|
|
} else if channel.index == 7 && channel.role > 0 {
|
|
|
|
|
Toggle("Channel 7 Included", isOn: $includeChannel7)
|
|
|
|
|
.toggleStyle(.switch)
|
|
|
|
|
.labelsHidden()
|
|
|
|
|
.disabled(channel.role == 1)
|
|
|
|
|
Text(((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)").camelCaseToWords()).fixedSize()
|
|
|
|
|
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
2025-06-15 20:29:47 -07:00
|
|
|
Image(systemName: "lock.slash.fill")
|
2023-08-31 22:39:51 -07:00
|
|
|
.foregroundColor(.red)
|
|
|
|
|
} else {
|
|
|
|
|
Image(systemName: "lock.fill")
|
|
|
|
|
.foregroundColor(.green)
|
2022-09-29 07:17:07 -07:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-31 22:39:51 -07:00
|
|
|
Spacer()
|
2022-09-29 07:17:07 -07:00
|
|
|
}
|
2022-11-08 12:48:16 -08:00
|
|
|
}
|
2023-08-31 22:39:51 -07:00
|
|
|
}
|
2022-11-05 08:26:27 -07:00
|
|
|
|
2023-08-31 22:39:51 -07:00
|
|
|
let qrImage = qrCodeImage.generateQRCode(from: channelsUrl)
|
|
|
|
|
VStack {
|
|
|
|
|
if node != nil {
|
2024-04-02 23:43:00 -07:00
|
|
|
Toggle(isOn: $replaceChannels) {
|
|
|
|
|
Label(replaceChannels ? "Replace Channels" : "Add Channels", systemImage: replaceChannels ? "arrow.triangle.2.circlepath.circle" : "plus.app")
|
|
|
|
|
}
|
|
|
|
|
.tint(.accentColor)
|
|
|
|
|
.toggleStyle(.button)
|
|
|
|
|
.buttonStyle(.bordered)
|
|
|
|
|
.buttonBorderShape(.capsule)
|
|
|
|
|
.controlSize(.large)
|
|
|
|
|
.padding(.top)
|
|
|
|
|
.padding(.bottom)
|
2024-05-29 16:40:07 -05:00
|
|
|
|
2023-08-31 22:39:51 -07:00
|
|
|
ShareLink("Share QR Code & Link",
|
|
|
|
|
item: Image(uiImage: qrImage),
|
|
|
|
|
subject: Text("Meshtastic Node \(node?.user?.shortName ?? "????") has shared channels with you"),
|
|
|
|
|
message: Text(channelsUrl),
|
|
|
|
|
preview: SharePreview("Meshtastic Node \(node?.user?.shortName ?? "????") has shared channels with you",
|
|
|
|
|
image: Image(uiImage: qrImage))
|
|
|
|
|
)
|
|
|
|
|
.buttonStyle(.bordered)
|
|
|
|
|
.buttonBorderShape(.capsule)
|
|
|
|
|
.controlSize(.large)
|
|
|
|
|
.padding(.bottom)
|
2023-03-06 10:33:18 -08:00
|
|
|
|
2023-08-31 22:39:51 -07:00
|
|
|
Image(uiImage: qrImage)
|
|
|
|
|
.resizable()
|
|
|
|
|
.scaledToFit()
|
|
|
|
|
.frame(
|
2025-06-22 20:19:42 -07:00
|
|
|
minWidth: smallest * (UIDevice.current.userInterfaceIdiom == .phone ? 0.75 : 0.6),
|
|
|
|
|
maxWidth: smallest * (UIDevice.current.userInterfaceIdiom == .phone ? 0.75 : 0.6),
|
|
|
|
|
minHeight: smallest * (UIDevice.current.userInterfaceIdiom == .phone ? 0.75 : 0.6),
|
|
|
|
|
maxHeight: smallest * (UIDevice.current.userInterfaceIdiom == .phone ? 0.75 : 0.6),
|
2023-08-31 22:39:51 -07:00
|
|
|
alignment: .top
|
|
|
|
|
)
|
2022-10-10 07:17:57 -07:00
|
|
|
}
|
2022-09-27 08:09:35 -07:00
|
|
|
}
|
2022-10-10 18:59:33 -07:00
|
|
|
}
|
2022-11-08 12:48:16 -08:00
|
|
|
}
|
2025-06-22 20:19:42 -07:00
|
|
|
.sheet(isPresented: $showingHelp) {
|
|
|
|
|
ChannelsHelp()
|
|
|
|
|
.presentationDetents([.large])
|
|
|
|
|
.presentationDragIndicator(.visible)
|
|
|
|
|
}
|
|
|
|
|
.safeAreaInset(edge: .bottom, alignment: .leading) {
|
|
|
|
|
HStack {
|
|
|
|
|
Button(action: {
|
|
|
|
|
withAnimation {
|
|
|
|
|
showingHelp = !showingHelp
|
|
|
|
|
}
|
|
|
|
|
}) {
|
|
|
|
|
Image(systemName: !showingHelp ? "questionmark.circle" : "questionmark.circle.fill")
|
|
|
|
|
.padding(.vertical, 5)
|
|
|
|
|
}
|
|
|
|
|
.tint(Color(UIColor.secondarySystemBackground))
|
|
|
|
|
.foregroundColor(.accentColor)
|
|
|
|
|
.buttonStyle(.borderedProminent)
|
|
|
|
|
}
|
|
|
|
|
.controlSize(.regular)
|
|
|
|
|
.padding(5)
|
|
|
|
|
}
|
|
|
|
|
.padding(.bottom, 5)
|
2025-05-08 22:50:44 -07:00
|
|
|
.navigationTitle("Generate QR Code")
|
2022-11-08 12:48:16 -08:00
|
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
|
|
|
.navigationBarItems(trailing:
|
|
|
|
|
ZStack {
|
Transports Interface to Support TCP for all Platforms and Serial on Mac (#1341)
* Initial implementation of transports
* Initial LogRadio implementation
* Fixes for Settings view (caused by debug commenting)
* Refinement of the object and actor model
* Connect view text and tab updates
* Fix mac catalyst and tests
* Warning and logging clean-up
* In progress commit
* Serial Transport and Reconnect draft work
* Serial transport and reconnection draft work
* Quick fix for BLE - still more work to do
* interim commit
* More in progress changes
* Minor improvements
* Pretty good initial implementation
* Bump version beyond the app store
* Fix for disconnection swipeAction
* Tweaks to TCPConnection implementation
* Retry for NONCE_ONLY_DB
* Revert json string change
* Simplified some of the API + "Anti-discovery"
* Tweaks for devices leaving the discovery process
* Bump version
* iOS26 Tweaks
* Tweaks and bug fixes
* Add link with slash sf symbol
* update symbol image on connect view
* BLE disconnect handling
* Log privacy attributes
* Onboarding and minor fixes.
* change database to nodes, add emoji to tcp logs
* Error handling improvements
* More logging emojis
* Suppressed unnecessary errors on disconnect
* Heartbeat emoji
* Add bluetooth symbol
* add privacy attributes to [TCP] logs, add custom bluetooth logo
* Improve routing logs
* Emoji for connect logs
* Heartbeat emoji
* Add CBCentralManagerScanOptionAllowDuplicatesKey options to central for bluetooth
* fix nav errors by switching from observableobject to state
* Update connection indicator icon
* fix for BLE disconnects
* Connection process fixes
* More fixes/tweaks to connection process
* Strict concurrency
* Fix some warnings, remove wifi warning
* delete stale keys
* interim commit
* Update privacy for log, fix wrong space
* fix a couple of linting items
* Switch to targeted
* interim commit
* BLE Signal strenth on connect view
* Remove BLE RSSI from long press menu
* Modem lights
* minor spacing tweak
* Additional BLE logging and a scanning fix.
* Discovery and BLE RSSI improvements
* Background suspension
* Update isConnected to enable UI during db load
* update protobufs
* Replace config if statements with switches, Fix unknown module config logging, make dark mode modem circle stroke color white so they are visible
* Additional logging cleanup
* hast
* Set unmessagable to true if the longname has the unmessagable emoji
* Connect error handling improvements
* Admin popup list icon and activity lights updates
* Revert use of .toolbar back to .navigationBarItems
* More public logging
* Better BLE error handling
* Node DB progress meter
* minor tweak to activity light interaction timing
* Fix comment linting, remove stale keys
* Remove stale keys
* Easy linting fixes
* Two more simple linting fixes
* clean up meshtasticapp
* More public logging
* Replay config
* Logging
* Fix for unselected node on Settings
* Tweak to progress meter based on device idiom
* Update protos
* Session replay redaction of messages
* Serial fix for old devices, and a let statement
* Mask text too
* Fix typo
* BLE poweredOff is now an auto-reconnectable error
* Update logging
* Fix for peerRemovedPairingInformation
* Logging for BLE peripheral:didUpdateValueFor errors.
* Fix for inconsistent swipe disconnect behavior
* periperal:didUpdateValueFor error handling
* Fix for BLEConnection continuation guarding
* BLEConnection actor deadlock on disconnect
* Heartbeat nonce
* Fix for swipe disconnect and task cancellation
* Fix for swipe actions not honoring .disabled()
* Tell BLETransport when BLEConnection is cancelled
* Update navigation logging
* Logging updates
* Bump version to 2.7.0
* Organize into folders and heartbeat stuff
* Minor improvements to manual TCP connection
* Auto-connect toggle
* Possible BLE bug, still waiting to see in logs
* Concurrency tweaks
* Concurrency improvements
* requestDeviceMetadata fix. fixes remote admin
* Minor typo fixes
* "All" button for log filters: category and level
* More robust continuation handling for BLE
* @FetchRequest based ChannelMessageList
* Update info.plist and device hardware file
* Move auto connect toggle to app settings and debug mode, tint properly with the accent color
* Add label to auto connect toggle
* Update log for node info received from ourselves over the mesh
* Remove unused scrollViewProxy
* Update Meshtastic/Views/Onboarding/DeviceOnboarding.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update target for connect view
* Properly Set datadog environment
* Comment out ble manager
* Adjust cyclomatic complexity thresholds in .swiftlint.yml
* Linting fixes, delete ble manager
* Make session replay debug only
---------
Co-authored-by: jake-b <jake-b@users.noreply.github.com>
Co-authored-by: jake <jake@jakes-Mac-mini.local>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-27 08:09:02 -07:00
|
|
|
ConnectedDevice(deviceConnected: accessoryManager.isConnected, name: accessoryManager.activeConnection?.device.shortName ?? "?")
|
2022-11-08 12:48:16 -08:00
|
|
|
})
|
|
|
|
|
.onAppear {
|
2023-03-06 13:26:04 -08:00
|
|
|
generateChannelSet()
|
2022-09-27 08:09:35 -07:00
|
|
|
}
|
2024-10-05 15:50:57 -07:00
|
|
|
.onChange(of: includeChannel0) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel1) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel2) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel3) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel4) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel5) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel6) { generateChannelSet() }
|
|
|
|
|
.onChange(of: includeChannel7) { generateChannelSet() }
|
|
|
|
|
.onChange(of: replaceChannels) { generateChannelSet() }
|
2022-09-27 08:09:35 -07:00
|
|
|
}
|
|
|
|
|
}
|
2023-03-06 13:26:04 -08:00
|
|
|
func generateChannelSet() {
|
2022-10-10 18:59:33 -07:00
|
|
|
channelSet = ChannelSet()
|
2022-10-10 13:40:18 -07:00
|
|
|
var loRaConfig = Config.LoRaConfig()
|
2022-10-14 22:18:28 -07:00
|
|
|
loRaConfig.region = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0))!.protoEnumValue()
|
|
|
|
|
loRaConfig.modemPreset = ModemPresets(rawValue: Int(node?.loRaConfig?.modemPreset ?? 0))!.protoEnumValue()
|
|
|
|
|
loRaConfig.bandwidth = UInt32(node?.loRaConfig?.bandwidth ?? 0)
|
|
|
|
|
loRaConfig.spreadFactor = UInt32(node?.loRaConfig?.spreadFactor ?? 0)
|
|
|
|
|
loRaConfig.codingRate = UInt32(node?.loRaConfig?.codingRate ?? 0)
|
|
|
|
|
loRaConfig.frequencyOffset = node?.loRaConfig?.frequencyOffset ?? 0
|
|
|
|
|
loRaConfig.hopLimit = UInt32(node?.loRaConfig?.hopLimit ?? 3)
|
|
|
|
|
loRaConfig.txEnabled = node?.loRaConfig?.txEnabled ?? false
|
|
|
|
|
loRaConfig.txPower = node?.loRaConfig?.txPower ?? 0
|
2022-10-22 13:05:54 -07:00
|
|
|
loRaConfig.usePreset = node?.loRaConfig?.usePreset ?? true
|
2022-10-14 22:18:28 -07:00
|
|
|
loRaConfig.channelNum = UInt32(node?.loRaConfig?.channelNum ?? 0)
|
2023-03-11 09:26:52 -08:00
|
|
|
loRaConfig.sx126XRxBoostedGain = node?.loRaConfig?.sx126xRxBoostedGain ?? false
|
2024-01-20 21:32:36 -08:00
|
|
|
loRaConfig.ignoreMqtt = node?.loRaConfig?.ignoreMqtt ?? false
|
2025-09-07 16:04:25 -07:00
|
|
|
loRaConfig.overrideFrequency = node?.loRaConfig?.overrideFrequency ?? 0.0
|
2022-10-10 13:40:18 -07:00
|
|
|
channelSet.loraConfig = loRaConfig
|
2023-02-12 20:11:50 -08:00
|
|
|
if node?.myInfo?.channels != nil && node?.myInfo?.channels?.count ?? 0 > 0 {
|
2024-07-07 09:40:06 -07:00
|
|
|
for ch in node?.myInfo?.channels?.array as? [ChannelEntity] ?? [] where ch.role > 0 {
|
|
|
|
|
var includeChannel = false
|
|
|
|
|
switch ch.index {
|
|
|
|
|
case 0:
|
|
|
|
|
if includeChannel0 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 1:
|
|
|
|
|
if includeChannel1 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 2:
|
|
|
|
|
if includeChannel2 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 3:
|
|
|
|
|
if includeChannel3 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 4:
|
|
|
|
|
if includeChannel4 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 5:
|
|
|
|
|
if includeChannel5 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 6:
|
|
|
|
|
if includeChannel6 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
case 7:
|
|
|
|
|
if includeChannel7 {
|
|
|
|
|
includeChannel = true
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
includeChannel = false
|
|
|
|
|
}
|
|
|
|
|
if includeChannel {
|
2024-06-02 18:32:14 -07:00
|
|
|
var channelSettings = ChannelSettings()
|
|
|
|
|
channelSettings.name = ch.name!
|
|
|
|
|
channelSettings.psk = ch.psk!
|
|
|
|
|
channelSettings.id = UInt32(ch.id)
|
|
|
|
|
channelSet.settings.append(channelSettings)
|
2022-10-10 18:59:33 -07:00
|
|
|
}
|
2022-10-10 13:40:18 -07:00
|
|
|
}
|
2024-06-02 18:32:14 -07:00
|
|
|
guard let settingsString = try? channelSet.serializedData().base64EncodedString() else {
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-06-18 17:00:25 -07:00
|
|
|
channelsUrl = ("https://meshtastic.org/e/\(replaceChannels ? "" : "?add=true")#\(settingsString.base64ToBase64url())")
|
2022-10-10 13:40:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-27 08:09:35 -07:00
|
|
|
}
|