mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Split channel form out into its own view
This commit is contained in:
parent
e4284d9741
commit
8d2b705068
3 changed files with 276 additions and 240 deletions
|
|
@ -111,6 +111,7 @@
|
|||
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; };
|
||||
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; };
|
||||
DD93800B2BA3F968008BEC06 /* NodeMapContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD93800A2BA3F968008BEC06 /* NodeMapContent.swift */; };
|
||||
DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD93800D2BA74D0C008BEC06 /* ChannelForm.swift */; };
|
||||
DD94B7402ACCE3BE00DCD1D1 /* MapSettingsForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD94B73F2ACCE3BE00DCD1D1 /* MapSettingsForm.swift */; };
|
||||
DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FBC296E6B01007C176F /* EmojiOnlyTextField.swift */; };
|
||||
DD964FBF296E76EF007C176F /* WaypointFormMapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FBE296E76EF007C176F /* WaypointFormMapKit.swift */; };
|
||||
|
|
@ -362,6 +363,7 @@
|
|||
DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = "<group>"; };
|
||||
DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationManager.swift; sourceTree = "<group>"; };
|
||||
DD93800A2BA3F968008BEC06 /* NodeMapContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMapContent.swift; sourceTree = "<group>"; };
|
||||
DD93800D2BA74D0C008BEC06 /* ChannelForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelForm.swift; sourceTree = "<group>"; };
|
||||
DD94B73F2ACCE3BE00DCD1D1 /* MapSettingsForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapSettingsForm.swift; sourceTree = "<group>"; };
|
||||
DD964FBC296E6B01007C176F /* EmojiOnlyTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiOnlyTextField.swift; sourceTree = "<group>"; };
|
||||
DD964FBE296E76EF007C176F /* WaypointFormMapKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointFormMapKit.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -560,21 +562,6 @@
|
|||
path = CoreData;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DD2100802B0E676E00F2F116 /* Routes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD2100832B0E67AD00F2F116 /* RouteMap */,
|
||||
);
|
||||
path = Routes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DD2100832B0E67AD00F2F116 /* RouteMap */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = RouteMap;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DD47E3CA26F0E50300029299 /* Nodes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -604,7 +591,7 @@
|
|||
DD4A911C2708C57100501B7E /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD2100802B0E676E00F2F116 /* Routes */,
|
||||
DD93800C2BA74CE3008BEC06 /* Channels */,
|
||||
DD97E96728EFE9A00056DDA4 /* About.swift */,
|
||||
DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */,
|
||||
DD4A911D2708C65400501B7E /* AppSettings.swift */,
|
||||
|
|
@ -747,6 +734,14 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DD93800C2BA74CE3008BEC06 /* Channels */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD93800D2BA74D0C008BEC06 /* ChannelForm.swift */,
|
||||
);
|
||||
path = Channels;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDAD49EB2AFAE82500B4425D /* Map */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -1229,6 +1224,7 @@
|
|||
DDB75A0F2A05920E006ED576 /* FileManager.swift in Sources */,
|
||||
DD1933782B084F4200771CD5 /* Measurement.swift in Sources */,
|
||||
DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */,
|
||||
DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */,
|
||||
DD41A61529AB0035003C5A37 /* NodeWeatherForecast.swift in Sources */,
|
||||
DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */,
|
||||
DD4640202AFF10F4002A5ECB /* WaypointForm.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -40,18 +40,15 @@ struct Channels: View {
|
|||
@State private var channelRole = 0
|
||||
@State private var uplink = false
|
||||
@State private var downlink = false
|
||||
|
||||
@State private var positionPrecision = 32.0
|
||||
@State private var preciseLocation = true
|
||||
@State private var positionsEnabled = true
|
||||
@State private var supportedVersion = true
|
||||
|
||||
/// Minimum Version for granular position configuration
|
||||
@State var minimumVersion = "2.2.24"
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
let supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame
|
||||
|
||||
VStack {
|
||||
List {
|
||||
|
|
@ -80,7 +77,10 @@ struct Channels: View {
|
|||
channelName = channel.name ?? ""
|
||||
uplink = channel.uplinkEnabled
|
||||
downlink = channel.downlinkEnabled
|
||||
hasChanges = false
|
||||
|
||||
print("Position Precision \(channel.positionPrecision)")
|
||||
//self.positionPrecision = State(initialValue: Double(self.channel.positionPrecision))
|
||||
positionPrecision = Double(channel.positionPrecision)
|
||||
if !supportedVersion && channelRole == 1 {
|
||||
positionPrecision = 32
|
||||
preciseLocation = true
|
||||
|
|
@ -91,21 +91,22 @@ struct Channels: View {
|
|||
preciseLocation = false
|
||||
positionsEnabled = false
|
||||
} else {
|
||||
positionPrecision = Double(channel.positionPrecision)
|
||||
if positionPrecision == 32 {
|
||||
preciseLocation = true
|
||||
positionsEnabled = true
|
||||
} else {
|
||||
preciseLocation = false
|
||||
}
|
||||
|
||||
if positionPrecision == 0 {
|
||||
positionsEnabled = false
|
||||
} else {
|
||||
positionsEnabled = true
|
||||
}
|
||||
}
|
||||
hasChanges = false
|
||||
isPresentingEditView = true
|
||||
|
||||
|
||||
}) {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
|
|
@ -138,224 +139,9 @@ struct Channels: View {
|
|||
.font(.largeTitle)
|
||||
.padding()
|
||||
#endif
|
||||
Form {
|
||||
Section(header: Text("channel details")) {
|
||||
HStack {
|
||||
Text("name")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Channel Name",
|
||||
text: $channelName
|
||||
)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: channelName, perform: { _ in
|
||||
channelName = channelName.replacing(" ", with: "")
|
||||
let totalBytes = channelName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 11 {
|
||||
let firstNBytes = Data(channelName.utf8.prefix(11))
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
// Set the channelName back to the last place where it was the right size
|
||||
channelName = maxBytesString
|
||||
}
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
HStack {
|
||||
Picker("Key Size", selection: $channelKeySize) {
|
||||
Text("Empty").tag(0)
|
||||
Text("Default").tag(-1)
|
||||
Text("1 byte").tag(1)
|
||||
Text("128 bit").tag(16)
|
||||
Text("192 bit").tag(24)
|
||||
Text("256 bit").tag(32)
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
Spacer()
|
||||
Button {
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
let key = generateChannelKey(size: channelKeySize)
|
||||
channelKey = key
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "lock.rotation")
|
||||
.font(.title)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.small)
|
||||
}
|
||||
HStack(alignment: .center) {
|
||||
Text("Key")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Key",
|
||||
text: $channelKey,
|
||||
axis: .vertical
|
||||
)
|
||||
.padding(6)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.textSelection(.enabled)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10.0)
|
||||
.stroke(
|
||||
hasValidKey ?
|
||||
Color.clear :
|
||||
Color.red
|
||||
, lineWidth: 2.0)
|
||||
|
||||
)
|
||||
.onChange(of: channelKey, perform: { _ in
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1{
|
||||
hasValidKey = true
|
||||
}
|
||||
else {
|
||||
hasValidKey = false
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
.disabled(channelKeySize <= 0)
|
||||
}
|
||||
HStack {
|
||||
if channelRole == 1 {
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Primary").tag(1)
|
||||
}
|
||||
.pickerStyle(.automatic)
|
||||
.disabled(true)
|
||||
} else {
|
||||
Text("Channel Role")
|
||||
Spacer()
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Disabled").tag(0)
|
||||
Text("Secondary").tag(2)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("position")) {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Toggle(isOn: $positionsEnabled) {
|
||||
Label(channelRole == 1 ? "Positions Enabled" : "Allow Position Requests", systemImage: positionsEnabled ? "mappin" : "mappin.slash")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(!supportedVersion)
|
||||
}
|
||||
|
||||
if positionsEnabled {
|
||||
VStack(alignment: .leading) {
|
||||
Toggle(isOn: $preciseLocation) {
|
||||
Label("Precise Location", systemImage: "scope")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(!supportedVersion)
|
||||
.listRowSeparator(.visible)
|
||||
.onChange(of: preciseLocation) { pl in
|
||||
if pl == false {
|
||||
positionPrecision = 13
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !preciseLocation {
|
||||
VStack(alignment: .leading) {
|
||||
Label("Approximate Location", systemImage: "location.slash.circle.fill")
|
||||
Slider(
|
||||
value: $positionPrecision,
|
||||
in: 11...16,
|
||||
step: 1
|
||||
)
|
||||
{
|
||||
} minimumValueLabel: {
|
||||
Image(systemName: "minus")
|
||||
} maximumValueLabel: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
Text(PositionPrecision(rawValue: Int(positionPrecision))?.description ?? "")
|
||||
.foregroundColor(.gray)
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Section(header: Text("mqtt")) {
|
||||
Toggle(isOn: $uplink) {
|
||||
Label("Uplink Enabled", systemImage: "arrowshape.up")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.listRowSeparator(.visible)
|
||||
|
||||
Toggle(isOn: $downlink) {
|
||||
Label("Downlink Enabled", systemImage: "arrowshape.down")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.listRowSeparator(.visible)
|
||||
}
|
||||
}
|
||||
ChannelForm(channelIndex: $channelIndex, channelName: $channelName, channelKeySize: $channelKeySize, channelKey: $channelKey, channelRole: $channelRole, uplink: $uplink, downlink: $downlink, positionPrecision: $positionPrecision, preciseLocation: $preciseLocation, positionsEnabled: $positionsEnabled, hasChanges: $hasChanges, hasValidKey: $hasValidKey, supportedVersion: $supportedVersion)
|
||||
.onAppear {
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1 {
|
||||
hasValidKey = true
|
||||
}
|
||||
else {
|
||||
hasValidKey = false
|
||||
}
|
||||
}
|
||||
.onChange(of: channelName) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
let key = generateChannelKey(size: channelKeySize)
|
||||
channelKey = key
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKey) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelRole) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: preciseLocation) { loc in
|
||||
if loc {
|
||||
positionPrecision = 32
|
||||
} else {
|
||||
positionPrecision = 14
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionPrecision) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionsEnabled) { pe in
|
||||
if pe {
|
||||
if positionPrecision == 0 {
|
||||
positionPrecision = 32
|
||||
}
|
||||
} else {
|
||||
positionPrecision = 0
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: uplink) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: downlink) { _ in
|
||||
hasChanges = true
|
||||
supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame
|
||||
}
|
||||
HStack {
|
||||
Button {
|
||||
|
|
|
|||
254
Meshtastic/Views/Settings/Channels/ChannelForm.swift
Normal file
254
Meshtastic/Views/Settings/Channels/ChannelForm.swift
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
//
|
||||
// ChannelForm.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 3/17/24.
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
#if canImport(MapKit)
|
||||
import MapKit
|
||||
#endif
|
||||
|
||||
struct ChannelForm: View {
|
||||
|
||||
@Binding var channelIndex: Int32
|
||||
@Binding var channelName: String
|
||||
@Binding var channelKeySize: Int
|
||||
@Binding var channelKey: String
|
||||
@Binding var channelRole: Int
|
||||
@Binding var uplink: Bool
|
||||
@Binding var downlink: Bool
|
||||
@Binding var positionPrecision: Double
|
||||
@Binding var preciseLocation: Bool
|
||||
@Binding var positionsEnabled: Bool
|
||||
|
||||
@Binding var hasChanges: Bool
|
||||
@Binding var hasValidKey: Bool
|
||||
|
||||
/// Minimum Version for granular position configuration
|
||||
@Binding var supportedVersion: Bool
|
||||
|
||||
var body: some View {
|
||||
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section(header: Text("channel details")) {
|
||||
HStack {
|
||||
Text("name")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Channel Name",
|
||||
text: $channelName
|
||||
)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: channelName, perform: { _ in
|
||||
channelName = channelName.replacing(" ", with: "")
|
||||
let totalBytes = channelName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 11 {
|
||||
let firstNBytes = Data(channelName.utf8.prefix(11))
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
// Set the channelName back to the last place where it was the right size
|
||||
channelName = maxBytesString
|
||||
}
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
HStack {
|
||||
Picker("Key Size", selection: $channelKeySize) {
|
||||
Text("Empty").tag(0)
|
||||
Text("Default").tag(-1)
|
||||
Text("1 byte").tag(1)
|
||||
Text("128 bit").tag(16)
|
||||
Text("192 bit").tag(24)
|
||||
Text("256 bit").tag(32)
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
Spacer()
|
||||
Button {
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
let key = generateChannelKey(size: channelKeySize)
|
||||
channelKey = key
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "lock.rotation")
|
||||
.font(.title)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.small)
|
||||
}
|
||||
HStack(alignment: .center) {
|
||||
Text("Key")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Key",
|
||||
text: $channelKey,
|
||||
axis: .vertical
|
||||
)
|
||||
.padding(6)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.textSelection(.enabled)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10.0)
|
||||
.stroke(
|
||||
hasValidKey ?
|
||||
Color.clear :
|
||||
Color.red
|
||||
, lineWidth: 2.0)
|
||||
|
||||
)
|
||||
.onChange(of: channelKey, perform: { _ in
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1{
|
||||
hasValidKey = true
|
||||
}
|
||||
else {
|
||||
hasValidKey = false
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
.disabled(channelKeySize <= 0)
|
||||
}
|
||||
HStack {
|
||||
if channelRole == 1 {
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Primary").tag(1)
|
||||
}
|
||||
.pickerStyle(.automatic)
|
||||
.disabled(true)
|
||||
} else {
|
||||
Text("Channel Role")
|
||||
Spacer()
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Disabled").tag(0)
|
||||
Text("Secondary").tag(2)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("position")) {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Toggle(isOn: $positionsEnabled) {
|
||||
Label(channelRole == 1 ? "Positions Enabled" : "Allow Position Requests", systemImage: positionsEnabled ? "mappin" : "mappin.slash")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(!supportedVersion)
|
||||
}
|
||||
|
||||
if positionsEnabled {
|
||||
VStack(alignment: .leading) {
|
||||
Toggle(isOn: $preciseLocation) {
|
||||
Label("Precise Location", systemImage: "scope")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(!supportedVersion)
|
||||
.listRowSeparator(.visible)
|
||||
.onChange(of: preciseLocation) { pl in
|
||||
if pl == false {
|
||||
positionPrecision = 13
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !preciseLocation {
|
||||
VStack(alignment: .leading) {
|
||||
Label("Approximate Location", systemImage: "location.slash.circle.fill")
|
||||
Slider(value: $positionPrecision, in: 11...16, step: 1) {
|
||||
} minimumValueLabel: {
|
||||
Image(systemName: "minus")
|
||||
} maximumValueLabel: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
Text(PositionPrecision(rawValue: Int(positionPrecision))?.description ?? "")
|
||||
.foregroundColor(.gray)
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Section(header: Text("mqtt")) {
|
||||
Toggle(isOn: $uplink) {
|
||||
Label("Uplink Enabled", systemImage: "arrowshape.up")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.listRowSeparator(.visible)
|
||||
|
||||
Toggle(isOn: $downlink) {
|
||||
Label("Downlink Enabled", systemImage: "arrowshape.down")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.listRowSeparator(.visible)
|
||||
}
|
||||
}
|
||||
.onChange(of: channelName) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
let key = generateChannelKey(size: channelKeySize)
|
||||
channelKey = key
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKey) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelRole) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: preciseLocation) { loc in
|
||||
if loc == true {
|
||||
positionPrecision = 32
|
||||
} else {
|
||||
positionPrecision = 14
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionPrecision) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionsEnabled) { pe in
|
||||
if pe {
|
||||
if positionPrecision == 0 {
|
||||
positionPrecision = 32
|
||||
}
|
||||
} else {
|
||||
positionPrecision = 0
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: uplink) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: downlink) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onAppear {
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1 {
|
||||
hasValidKey = true
|
||||
}
|
||||
else {
|
||||
hasValidKey = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.fraction(0.45), .fraction(0.65)])
|
||||
.presentationDragIndicator(.visible)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue