mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
commit
5013ccc294
6 changed files with 178 additions and 94 deletions
|
|
@ -1054,22 +1054,44 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
public func saveChannelSet(base64UrlString: String) -> Bool {
|
||||
|
||||
if isConnected {
|
||||
var decodedString = base64UrlString.base64urlToBase64()
|
||||
|
||||
//Before we get started delete the existing channels from the myNodeInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedPeripheral.num))
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context!.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count == 1 {
|
||||
|
||||
let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as! NSMutableOrderedSet
|
||||
mutableChannels.removeAllObjects()
|
||||
fetchedMyInfo[0].channels = mutableChannels
|
||||
fetchedMyInfo[0].objectWillChange.send()
|
||||
do {
|
||||
try context!.save()
|
||||
|
||||
} catch {
|
||||
print("Failed to clear existing channels from local app database")
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
|
||||
let decodedString = base64UrlString.base64urlToBase64()
|
||||
if let decodedData = Data(base64Encoded: decodedString) {
|
||||
do {
|
||||
var channelSet: ChannelSet = try ChannelSet(serializedData: decodedData)
|
||||
print(channelSet)
|
||||
var i:Int32 = 0
|
||||
for cs in channelSet.settings {
|
||||
i += 1
|
||||
var chan = Channel()
|
||||
i += 1
|
||||
chan.settings = cs
|
||||
chan.index = i
|
||||
if i == 1 {
|
||||
chan.role = Channel.Role.primary
|
||||
} else {
|
||||
chan.role = Channel.Role.secondary
|
||||
}
|
||||
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.setChannel = chan
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
|
|
@ -1088,12 +1110,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
toRadio.packet = meshPacket
|
||||
let binaryData: Data = try! toRadio.serializedData()
|
||||
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
|
||||
//let timer1 = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { timer in
|
||||
self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse)
|
||||
MeshLogger.log("💾 Saved a Channel for: \(String(self.connectedPeripheral.num))")
|
||||
//}
|
||||
}
|
||||
print(chan)
|
||||
}
|
||||
// Save the LoRa Config and the device will reboot
|
||||
var adminPacket = AdminMessage()
|
||||
|
|
@ -1105,7 +1124,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = true
|
||||
meshPacket.wantAck = false
|
||||
meshPacket.hopLimit = 0
|
||||
|
||||
var dataMessage = DataMessage()
|
||||
|
|
@ -1118,10 +1137,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
toRadio.packet = meshPacket
|
||||
let binaryData: Data = try! toRadio.serializedData()
|
||||
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
|
||||
// let timer1 = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in
|
||||
self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse)
|
||||
self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse)
|
||||
MeshLogger.log("💾 Saved a LoRaConfig for: \(String(self.connectedPeripheral.num))")
|
||||
// }
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
|
||||
func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
if channel.isInitialized && channel.hasSettings {
|
||||
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
|
||||
|
||||
let fetchedMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum)
|
||||
|
|
@ -770,13 +770,11 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
newChannel.name = channel.settings.name
|
||||
newChannel.role = Int32(channel.role.rawValue)
|
||||
newChannel.psk = channel.settings.psk
|
||||
|
||||
|
||||
let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as! NSMutableOrderedSet
|
||||
// if channel.role.rawValue == 1 {
|
||||
// mutableChannels.removeAllObjects()
|
||||
// }
|
||||
|
||||
if channel.index == 1 {
|
||||
//mutableChannels.removeAllObjects()
|
||||
}
|
||||
|
||||
mutableChannels.add(newChannel)
|
||||
fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet
|
||||
|
|
@ -1254,6 +1252,12 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
do {
|
||||
|
||||
let fetchedUsers = try context.fetch(messageUsers) as! [UserEntity]
|
||||
|
||||
if fetchedUsers.count <= 1 && fetchedUsers.first(where: { $0.num == packet.from }) == nil {
|
||||
|
||||
print("Message from another mesh, unable to manage for now")
|
||||
return
|
||||
}
|
||||
|
||||
let newMessage = MessageEntity(context: context)
|
||||
newMessage.messageId = Int64(packet.id)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21279" systemVersion="21G115" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21279" systemVersion="22A380" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
|
||||
|
|
@ -77,6 +77,7 @@
|
|||
<attribute name="ackTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="admin" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="adminDescription" optional="YES" attributeType="String"/>
|
||||
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="messagePayload" optional="YES" attributeType="String" defaultValueString=""/>
|
||||
|
|
|
|||
|
|
@ -435,39 +435,57 @@ struct Config {
|
|||
|
||||
///
|
||||
/// Enable WiFi (disables Bluetooth)
|
||||
var wifiEnabled: Bool = false
|
||||
var wifiEnabled: Bool {
|
||||
get {return _storage._wifiEnabled}
|
||||
set {_uniqueStorage()._wifiEnabled = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// If set, this node will try to join the specified wifi network and
|
||||
/// acquire an address via DHCP
|
||||
var wifiSsid: String = String()
|
||||
var wifiSsid: String {
|
||||
get {return _storage._wifiSsid}
|
||||
set {_uniqueStorage()._wifiSsid = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// If set, will be use to authenticate to the named wifi
|
||||
var wifiPsk: String = String()
|
||||
var wifiPsk: String {
|
||||
get {return _storage._wifiPsk}
|
||||
set {_uniqueStorage()._wifiPsk = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org`
|
||||
var ntpServer: String = String()
|
||||
var ntpServer: String {
|
||||
get {return _storage._ntpServer}
|
||||
set {_uniqueStorage()._ntpServer = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// Enable Ethernet
|
||||
var ethEnabled: Bool = false
|
||||
var ethEnabled: Bool {
|
||||
get {return _storage._ethEnabled}
|
||||
set {_uniqueStorage()._ethEnabled = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// acquire an address via DHCP or assign static
|
||||
var ethMode: Config.NetworkConfig.EthMode = .dhcp
|
||||
var ethMode: Config.NetworkConfig.EthMode {
|
||||
get {return _storage._ethMode}
|
||||
set {_uniqueStorage()._ethMode = newValue}
|
||||
}
|
||||
|
||||
///
|
||||
/// struct to keep static address
|
||||
var ethConfig: Config.NetworkConfig.NetworkConfig {
|
||||
get {return _ethConfig ?? Config.NetworkConfig.NetworkConfig()}
|
||||
set {_ethConfig = newValue}
|
||||
var ethConfig: Config.NetworkConfig {
|
||||
get {return _storage._ethConfig ?? Config.NetworkConfig()}
|
||||
set {_uniqueStorage()._ethConfig = newValue}
|
||||
}
|
||||
/// Returns true if `ethConfig` has been explicitly set.
|
||||
var hasEthConfig: Bool {return self._ethConfig != nil}
|
||||
var hasEthConfig: Bool {return _storage._ethConfig != nil}
|
||||
/// Clears the value of `ethConfig`. Subsequent reads from it will return its default value.
|
||||
mutating func clearEthConfig() {self._ethConfig = nil}
|
||||
mutating func clearEthConfig() {_uniqueStorage()._ethConfig = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
|
|
@ -545,7 +563,7 @@ struct Config {
|
|||
|
||||
}
|
||||
|
||||
struct NetworkConfig {
|
||||
struct TcpConfig {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
|
@ -573,7 +591,7 @@ struct Config {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _ethConfig: Config.NetworkConfig.NetworkConfig? = nil
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -1161,7 +1179,7 @@ extension Config.PowerConfig: @unchecked Sendable {}
|
|||
extension Config.NetworkConfig: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig.WiFiMode: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig.EthMode: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig.NetworkConfig: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig.TcpConfig: @unchecked Sendable {}
|
||||
extension Config.DisplayConfig: @unchecked Sendable {}
|
||||
extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {}
|
||||
extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {}
|
||||
|
|
@ -1557,61 +1575,105 @@ extension Config.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
8: .standard(proto: "eth_config"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _wifiEnabled: Bool = false
|
||||
var _wifiSsid: String = String()
|
||||
var _wifiPsk: String = String()
|
||||
var _ntpServer: String = String()
|
||||
var _ethEnabled: Bool = false
|
||||
var _ethMode: Config.NetworkConfig.EthMode = .dhcp
|
||||
var _ethConfig: Config.NetworkConfig? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_wifiEnabled = source._wifiEnabled
|
||||
_wifiSsid = source._wifiSsid
|
||||
_wifiPsk = source._wifiPsk
|
||||
_ntpServer = source._ntpServer
|
||||
_ethEnabled = source._ethEnabled
|
||||
_ethMode = source._ethMode
|
||||
_ethConfig = source._ethConfig
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &self.wifiEnabled) }()
|
||||
case 3: try { try decoder.decodeSingularStringField(value: &self.wifiSsid) }()
|
||||
case 4: try { try decoder.decodeSingularStringField(value: &self.wifiPsk) }()
|
||||
case 5: try { try decoder.decodeSingularStringField(value: &self.ntpServer) }()
|
||||
case 6: try { try decoder.decodeSingularBoolField(value: &self.ethEnabled) }()
|
||||
case 7: try { try decoder.decodeSingularEnumField(value: &self.ethMode) }()
|
||||
case 8: try { try decoder.decodeSingularMessageField(value: &self._ethConfig) }()
|
||||
default: break
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &_storage._wifiEnabled) }()
|
||||
case 3: try { try decoder.decodeSingularStringField(value: &_storage._wifiSsid) }()
|
||||
case 4: try { try decoder.decodeSingularStringField(value: &_storage._wifiPsk) }()
|
||||
case 5: try { try decoder.decodeSingularStringField(value: &_storage._ntpServer) }()
|
||||
case 6: try { try decoder.decodeSingularBoolField(value: &_storage._ethEnabled) }()
|
||||
case 7: try { try decoder.decodeSingularEnumField(value: &_storage._ethMode) }()
|
||||
case 8: try { try decoder.decodeSingularMessageField(value: &_storage._ethConfig) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if self.wifiEnabled != false {
|
||||
try visitor.visitSingularBoolField(value: self.wifiEnabled, fieldNumber: 1)
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if _storage._wifiEnabled != false {
|
||||
try visitor.visitSingularBoolField(value: _storage._wifiEnabled, fieldNumber: 1)
|
||||
}
|
||||
if !_storage._wifiSsid.isEmpty {
|
||||
try visitor.visitSingularStringField(value: _storage._wifiSsid, fieldNumber: 3)
|
||||
}
|
||||
if !_storage._wifiPsk.isEmpty {
|
||||
try visitor.visitSingularStringField(value: _storage._wifiPsk, fieldNumber: 4)
|
||||
}
|
||||
if !_storage._ntpServer.isEmpty {
|
||||
try visitor.visitSingularStringField(value: _storage._ntpServer, fieldNumber: 5)
|
||||
}
|
||||
if _storage._ethEnabled != false {
|
||||
try visitor.visitSingularBoolField(value: _storage._ethEnabled, fieldNumber: 6)
|
||||
}
|
||||
if _storage._ethMode != .dhcp {
|
||||
try visitor.visitSingularEnumField(value: _storage._ethMode, fieldNumber: 7)
|
||||
}
|
||||
try { if let v = _storage._ethConfig {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 8)
|
||||
} }()
|
||||
}
|
||||
if !self.wifiSsid.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.wifiSsid, fieldNumber: 3)
|
||||
}
|
||||
if !self.wifiPsk.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.wifiPsk, fieldNumber: 4)
|
||||
}
|
||||
if !self.ntpServer.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.ntpServer, fieldNumber: 5)
|
||||
}
|
||||
if self.ethEnabled != false {
|
||||
try visitor.visitSingularBoolField(value: self.ethEnabled, fieldNumber: 6)
|
||||
}
|
||||
if self.ethMode != .dhcp {
|
||||
try visitor.visitSingularEnumField(value: self.ethMode, fieldNumber: 7)
|
||||
}
|
||||
try { if let v = self._ethConfig {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 8)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Config.NetworkConfig, rhs: Config.NetworkConfig) -> Bool {
|
||||
if lhs.wifiEnabled != rhs.wifiEnabled {return false}
|
||||
if lhs.wifiSsid != rhs.wifiSsid {return false}
|
||||
if lhs.wifiPsk != rhs.wifiPsk {return false}
|
||||
if lhs.ntpServer != rhs.ntpServer {return false}
|
||||
if lhs.ethEnabled != rhs.ethEnabled {return false}
|
||||
if lhs.ethMode != rhs.ethMode {return false}
|
||||
if lhs._ethConfig != rhs._ethConfig {return false}
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._wifiEnabled != rhs_storage._wifiEnabled {return false}
|
||||
if _storage._wifiSsid != rhs_storage._wifiSsid {return false}
|
||||
if _storage._wifiPsk != rhs_storage._wifiPsk {return false}
|
||||
if _storage._ntpServer != rhs_storage._ntpServer {return false}
|
||||
if _storage._ethEnabled != rhs_storage._ethEnabled {return false}
|
||||
if _storage._ethMode != rhs_storage._ethMode {return false}
|
||||
if _storage._ethConfig != rhs_storage._ethConfig {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1632,8 +1694,8 @@ extension Config.NetworkConfig.EthMode: SwiftProtobuf._ProtoNameProviding {
|
|||
]
|
||||
}
|
||||
|
||||
extension Config.NetworkConfig.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = Config.NetworkConfig.protoMessageName + ".NetworkConfig"
|
||||
extension Config.NetworkConfig.TcpConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = Config.NetworkConfig.protoMessageName + ".TcpConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "ip"),
|
||||
2: .same(proto: "gateway"),
|
||||
|
|
@ -1672,7 +1734,7 @@ extension Config.NetworkConfig.NetworkConfig: SwiftProtobuf.Message, SwiftProtob
|
|||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Config.NetworkConfig.NetworkConfig, rhs: Config.NetworkConfig.NetworkConfig) -> Bool {
|
||||
static func ==(lhs: Config.NetworkConfig.TcpConfig, rhs: Config.NetworkConfig.TcpConfig) -> Bool {
|
||||
if lhs.ip != rhs.ip {return false}
|
||||
if lhs.gateway != rhs.gateway {return false}
|
||||
if lhs.subnet != rhs.subnet {return false}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ struct PositionLog: View {
|
|||
//Add a table for mac and ipad
|
||||
VStack {
|
||||
Table(node.positions!.reversed() as! [PositionEntity]) {
|
||||
TableColumn("SeqNo") { position in
|
||||
TableColumn("Seq No") { position in
|
||||
Text(String(position.seqNo))
|
||||
}
|
||||
.width(75)
|
||||
//.width(75)
|
||||
TableColumn("Latitude") { position in
|
||||
Text(String(format: "%.6f", position.latitude ?? 0))
|
||||
}
|
||||
|
|
@ -39,15 +39,15 @@ struct PositionLog: View {
|
|||
TableColumn("Altitude") { position in
|
||||
Text(String(position.altitude))
|
||||
}
|
||||
.width(75)
|
||||
//.width(75)
|
||||
TableColumn("Sats") { position in
|
||||
Text(String(position.satsInView))
|
||||
}
|
||||
.width(75)
|
||||
//.width(75)
|
||||
TableColumn("Speed") { position in
|
||||
Text(String(position.speed))
|
||||
}
|
||||
.width(75)
|
||||
//.width(75)
|
||||
TableColumn("Heading") { position in
|
||||
Text(String(position.heading))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 1 Included", isOn: $includeChannel1)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -103,7 +103,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 2 Included", isOn: $includeChannel2)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -116,7 +116,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 3 Included", isOn: $includeChannel3)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -129,7 +129,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 4 Included", isOn: $includeChannel4)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -142,7 +142,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 5 Included", isOn: $includeChannel5)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -155,7 +155,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 6 Included", isOn: $includeChannel6)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
@ -168,7 +168,7 @@ struct ShareChannels: View {
|
|||
Toggle("Channel 7 Included", isOn: $includeChannel7)
|
||||
.toggleStyle(.switch)
|
||||
.labelsHidden()
|
||||
.disabled(channel.role == 0)
|
||||
.disabled(channel.role == 1)
|
||||
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
|
||||
if channel.psk?.hexDescription.count ?? 0 < 3 {
|
||||
Image(systemName: "lock.slash")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue