mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
SwiftLint Whitespace fixes
This commit is contained in:
parent
c3cbe9fb57
commit
fdade220de
104 changed files with 1644 additions and 1832 deletions
|
|
@ -867,7 +867,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ enum KeyboardType: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
|
||||
enum CenteringMode: Int, CaseIterable, Identifiable {
|
||||
|
||||
|
||||
case allAnnotations = 0
|
||||
case allPositions = 1
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
|
|
@ -55,13 +55,12 @@ enum CenteringMode: Int, CaseIterable, Identifiable {
|
|||
|
||||
enum MeshMapType: String, CaseIterable, Identifiable {
|
||||
|
||||
case standard = "standard"
|
||||
case standard = "standard"
|
||||
case mutedStandard = "mutedStandard"
|
||||
case hybrid = "hybrid"
|
||||
case hybridFlyover = "hybridFlyover"
|
||||
case satellite = "satellite"
|
||||
case satelliteFlyover = "satelliteFlyover"
|
||||
|
||||
|
||||
var id: String { self.rawValue }
|
||||
|
||||
|
|
@ -84,7 +83,7 @@ enum MeshMapType: String, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func MKMapTypeValue() -> MKMapType {
|
||||
|
||||
|
||||
switch self {
|
||||
case .standard:
|
||||
return MKMapType.standard
|
||||
|
|
@ -123,7 +122,7 @@ enum UserTrackingModes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func MKUserTrackingModeValue() -> MKUserTrackingMode {
|
||||
|
||||
|
||||
switch self {
|
||||
case .none:
|
||||
return MKUserTrackingMode.none
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ enum BluetoothModes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.BluetoothConfig.PairingMode {
|
||||
|
||||
switch self {
|
||||
|
||||
case .randomPin:
|
||||
return Config.BluetoothConfig.PairingMode.randomPin
|
||||
case .fixedPin:
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@
|
|||
import Foundation
|
||||
|
||||
// Default of 0 is unset
|
||||
enum ConfigPresets : Int, CaseIterable, Identifiable {
|
||||
enum ConfigPresets: Int, CaseIterable, Identifiable {
|
||||
|
||||
case unset = 0
|
||||
case rakRotaryEncoder = 1
|
||||
case cardKB = 2
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .unset:
|
||||
return NSLocalizedString("canned.messages.preset.manual", comment: "Manual Configuration")
|
||||
case .rakRotaryEncoder:
|
||||
|
|
@ -45,7 +45,7 @@ enum InputEventChars: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .none:
|
||||
return NSLocalizedString("inputevent.none", comment: "None")
|
||||
case .up:
|
||||
|
|
@ -66,7 +66,7 @@ enum InputEventChars: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> ModuleConfig.CannedMessageConfig.InputEventChar {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
case .none:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ enum ChannelRoles: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .disabled:
|
||||
return NSLocalizedString("channel.role.disabled", comment: "Disabled")
|
||||
case .primary:
|
||||
|
|
@ -28,9 +28,9 @@ enum ChannelRoles: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Channel.Role {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .disabled:
|
||||
return Channel.Role.disabled
|
||||
case .primary:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
|
|||
var name: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .client:
|
||||
return "Client"
|
||||
case .clientMute:
|
||||
|
|
@ -43,7 +43,7 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .client:
|
||||
return NSLocalizedString("device.role.client", comment: "Client (default) - App connected client.")
|
||||
case .clientMute:
|
||||
|
|
@ -62,9 +62,9 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DeviceConfig.Role {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .client:
|
||||
return Config.DeviceConfig.Role.client
|
||||
case .clientMute:
|
||||
|
|
@ -90,11 +90,11 @@ enum RebroadcastModes: Int, CaseIterable, Identifiable {
|
|||
case localOnly = 2
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
|
||||
|
||||
var name: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .all:
|
||||
return "All"
|
||||
case .allSkipDecoding:
|
||||
|
|
@ -117,7 +117,7 @@ enum RebroadcastModes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DeviceConfig.RebroadcastMode {
|
||||
|
||||
|
||||
switch self {
|
||||
case .all:
|
||||
return Config.DeviceConfig.RebroadcastMode.all
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
import Foundation
|
||||
|
||||
enum ScreenUnits: Int, CaseIterable, Identifiable {
|
||||
|
||||
|
||||
case metric = 0
|
||||
case imperial = 1
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
|
|
@ -24,7 +24,7 @@ enum ScreenUnits: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DisplayConfig.DisplayUnits {
|
||||
|
||||
|
||||
switch self {
|
||||
case .metric:
|
||||
return Config.DisplayConfig.DisplayUnits.metric
|
||||
|
|
@ -128,7 +128,7 @@ enum OledTypes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DisplayConfig.OledType {
|
||||
|
||||
|
||||
switch self {
|
||||
case .auto:
|
||||
return Config.DisplayConfig.OledType.oledAuto
|
||||
|
|
@ -166,7 +166,7 @@ enum DisplayModes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DisplayConfig.DisplayMode {
|
||||
|
||||
|
||||
switch self {
|
||||
case .defaultMode:
|
||||
return Config.DisplayConfig.DisplayMode.default
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ enum EthernetMode: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .dhcp:
|
||||
return "DHCP"
|
||||
case .staticip:
|
||||
|
|
@ -25,9 +25,9 @@ enum EthernetMode: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.NetworkConfig.AddressMode {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .dhcp:
|
||||
return Config.NetworkConfig.AddressMode.dhcp
|
||||
case .staticip:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
enum OutputIntervals: Int, CaseIterable, Identifiable {
|
||||
|
||||
|
||||
case unset = 0
|
||||
case oneSecond = 1000
|
||||
case twoSeconds = 2000
|
||||
|
|
@ -19,12 +19,12 @@ enum OutputIntervals: Int, CaseIterable, Identifiable {
|
|||
case fifteenSeconds = 15000
|
||||
case thirtySeconds = 30000
|
||||
case oneMinute = 60000
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .unset:
|
||||
return NSLocalizedString("unset", comment: "Unset")
|
||||
case .oneSecond:
|
||||
|
|
@ -63,7 +63,6 @@ enum SenderIntervals: Int, CaseIterable, Identifiable {
|
|||
case thirtyMinutes = 1800
|
||||
case oneHour = 3600
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
|
|
@ -118,7 +117,7 @@ enum UpdateIntervals: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .tenSeconds:
|
||||
return NSLocalizedString("interval.ten.seconds", comment: "Ten Seconds")
|
||||
case .fifteenSeconds:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
enum RegionCodes : Int, CaseIterable, Identifiable {
|
||||
enum RegionCodes: Int, CaseIterable, Identifiable {
|
||||
|
||||
case unset = 0
|
||||
case us = 1
|
||||
|
|
@ -65,11 +65,11 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func protoEnumValue() -> Config.LoRaConfig.RegionCode {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .unset:
|
||||
return Config.LoRaConfig.RegionCode.unset
|
||||
case .us:
|
||||
|
|
@ -106,96 +106,58 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
enum ModemPresets : Int, CaseIterable, Identifiable {
|
||||
|
||||
case LongFast = 0
|
||||
case LongSlow = 1
|
||||
case LongModerate = 7
|
||||
case VLongSlow = 2
|
||||
case MedSlow = 3
|
||||
case MedFast = 4
|
||||
case ShortSlow = 5
|
||||
case ShortFast = 6
|
||||
|
||||
enum ModemPresets: Int, CaseIterable, Identifiable {
|
||||
|
||||
case longFast = 0
|
||||
case longSlow = 1
|
||||
case longModerate = 7
|
||||
case vLongSlow = 2
|
||||
case medSlow = 3
|
||||
case medFast = 4
|
||||
case shortSlow = 5
|
||||
case shortFast = 6
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
case .LongFast:
|
||||
case .longFast:
|
||||
return "Long Range - Fast"
|
||||
case .LongSlow:
|
||||
case .longSlow:
|
||||
return "Long Range - Slow"
|
||||
case .LongModerate:
|
||||
case .longModerate:
|
||||
return "Long Range - Moderate"
|
||||
case .VLongSlow:
|
||||
case .vLongSlow:
|
||||
return "Very Long Range - Slow"
|
||||
case .MedSlow:
|
||||
case .medSlow:
|
||||
return "Medium Range - Slow"
|
||||
case .MedFast:
|
||||
case .medFast:
|
||||
return "Medium Range - Fast"
|
||||
case .ShortSlow:
|
||||
case .shortSlow:
|
||||
return "Short Range - Slow"
|
||||
case .ShortFast:
|
||||
case .shortFast:
|
||||
return "Short Range - Fast"
|
||||
}
|
||||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.LoRaConfig.ModemPreset {
|
||||
|
||||
switch self {
|
||||
|
||||
case .LongFast:
|
||||
return Config.LoRaConfig.ModemPreset.longFast
|
||||
case .LongSlow:
|
||||
return Config.LoRaConfig.ModemPreset.longSlow
|
||||
case .LongModerate:
|
||||
return Config.LoRaConfig.ModemPreset.longModerate
|
||||
case .VLongSlow:
|
||||
return Config.LoRaConfig.ModemPreset.veryLongSlow
|
||||
case .MedSlow:
|
||||
return Config.LoRaConfig.ModemPreset.mediumSlow
|
||||
case .MedFast:
|
||||
return Config.LoRaConfig.ModemPreset.mediumFast
|
||||
case .ShortSlow:
|
||||
return Config.LoRaConfig.ModemPreset.shortSlow
|
||||
case .ShortFast:
|
||||
return Config.LoRaConfig.ModemPreset.shortFast
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum HopValues : Int, CaseIterable, Identifiable {
|
||||
|
||||
case oneHop = 1
|
||||
case twoHops = 2
|
||||
case threeHops = 3
|
||||
case fourHops = 4
|
||||
case fiveHops = 5
|
||||
case sixHops = 6
|
||||
case sevenHops = 7
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
case .oneHop:
|
||||
return "One Hop"
|
||||
case .twoHops:
|
||||
return "Two Hops"
|
||||
case .threeHops:
|
||||
return "Three Hops"
|
||||
case .fourHops:
|
||||
return "Four Hops"
|
||||
case .fiveHops:
|
||||
return "Five Hops"
|
||||
case .sixHops:
|
||||
return "Six Hops"
|
||||
case .sevenHops:
|
||||
return "Seven Hops"
|
||||
}
|
||||
case .longFast:
|
||||
return Config.LoRaConfig.ModemPreset.longFast
|
||||
case .longSlow:
|
||||
return Config.LoRaConfig.ModemPreset.longSlow
|
||||
case .longModerate:
|
||||
return Config.LoRaConfig.ModemPreset.longModerate
|
||||
case .vLongSlow:
|
||||
return Config.LoRaConfig.ModemPreset.veryLongSlow
|
||||
case .medSlow:
|
||||
return Config.LoRaConfig.ModemPreset.mediumSlow
|
||||
case .medFast:
|
||||
return Config.LoRaConfig.ModemPreset.mediumFast
|
||||
case .shortSlow:
|
||||
return Config.LoRaConfig.ModemPreset.shortSlow
|
||||
case .shortFast:
|
||||
return Config.LoRaConfig.ModemPreset.shortFast
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ enum GpsFormats: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.DisplayConfig.GpsCoordinateFormat {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .gpsFormatDec:
|
||||
return Config.DisplayConfig.GpsCoordinateFormat.dec
|
||||
case .gpsFormatDms:
|
||||
|
|
@ -55,7 +55,6 @@ enum GpsFormats: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
enum GpsUpdateIntervals: Int, CaseIterable, Identifiable {
|
||||
|
||||
case fiveSeconds = 5
|
||||
|
|
@ -80,7 +79,7 @@ enum GpsUpdateIntervals: Int, CaseIterable, Identifiable {
|
|||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .fiveSeconds:
|
||||
return NSLocalizedString("interval.five.seconds", comment: "Five Seconds")
|
||||
case .tenSeconds:
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ enum RoutingError: Int, CaseIterable, Identifiable {
|
|||
var display: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .none:
|
||||
return NSLocalizedString("routing.acknowledged", comment: "Acknowledged")
|
||||
case .noRoute:
|
||||
|
|
@ -54,9 +54,9 @@ enum RoutingError: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> Routing.Error {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .none:
|
||||
return Routing.Error.none
|
||||
case .noRoute:
|
||||
|
|
@ -81,7 +81,7 @@ enum RoutingError: Int, CaseIterable, Identifiable {
|
|||
return Routing.Error.badRequest
|
||||
case .notAuthorized:
|
||||
return Routing.Error.notAuthorized
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,11 +65,11 @@ enum SerialBaudRates: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func protoEnumValue() -> ModuleConfig.SerialConfig.Serial_Baud {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .baudDefault:
|
||||
return ModuleConfig.SerialConfig.Serial_Baud.baudDefault
|
||||
case .baud110:
|
||||
|
|
@ -113,7 +113,7 @@ enum SerialModeTypes: Int, CaseIterable, Identifiable {
|
|||
case proto = 2
|
||||
case txtmsg = 3
|
||||
case nmea = 4
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
|
|
@ -132,9 +132,9 @@ enum SerialModeTypes: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
func protoEnumValue() -> ModuleConfig.SerialConfig.Serial_Mode {
|
||||
|
||||
|
||||
switch self {
|
||||
|
||||
|
||||
case .default:
|
||||
return ModuleConfig.SerialConfig.Serial_Mode.default
|
||||
case .simple:
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ enum WeatherConditions: Int, CaseIterable, Identifiable {
|
|||
var symbolName: String {
|
||||
get {
|
||||
switch self {
|
||||
|
||||
|
||||
case .clear:
|
||||
return "sparkle"
|
||||
case .cloudy:
|
||||
|
|
|
|||
|
|
@ -13,24 +13,24 @@ struct CsvDocument: FileDocument {
|
|||
static var readableContentTypes = [UTType.commaSeparatedText]
|
||||
|
||||
@State var csvData: String
|
||||
|
||||
|
||||
init(emptyCsv: String = "" ) {
|
||||
|
||||
|
||||
csvData = emptyCsv
|
||||
}
|
||||
|
||||
|
||||
init(configuration: ReadConfiguration) throws {
|
||||
|
||||
|
||||
if let data = configuration.file.regularFileContents {
|
||||
|
||||
|
||||
csvData = String(decoding: data, as: UTF8.self)
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
throw CocoaError(.fileReadCorruptFile)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
|
||||
let data = Data(csvData.utf8)
|
||||
return FileWrapper(regularFileWithContents: data)
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
import SwiftUI
|
||||
|
||||
func TelemetryToCsvFile(telemetry: [TelemetryEntity], metricsType: Int) -> String {
|
||||
func telemetryToCsvFile(telemetry: [TelemetryEntity], metricsType: Int) -> String {
|
||||
var csvString: String = ""
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
if metricsType == 0 {
|
||||
// Create Device Metrics Header
|
||||
csvString = "\(NSLocalizedString("battery.level", comment: "")), \(NSLocalizedString("voltage", comment: "")), \(NSLocalizedString("channel.utilization", comment: "")), \(NSLocalizedString("airtime", comment: "")), \(NSLocalizedString("timestamp", comment: ""))"
|
||||
for dm in telemetry{
|
||||
for dm in telemetry {
|
||||
if dm.metricsType == 0 {
|
||||
csvString += "\n"
|
||||
csvString += String(dm.batteryLevel)
|
||||
|
|
@ -31,7 +31,7 @@ func TelemetryToCsvFile(telemetry: [TelemetryEntity], metricsType: Int) -> Strin
|
|||
} else if metricsType == 1 {
|
||||
// Create Environment Telemetry Header
|
||||
csvString = "Temperature, Relative Humidity, Barometric Pressure, Gas Resistance, \(NSLocalizedString("voltage", comment: "")), \(NSLocalizedString("current", comment: "")), \(NSLocalizedString("timestamp", comment: ""))"
|
||||
for dm in telemetry{
|
||||
for dm in telemetry {
|
||||
if dm.metricsType == 1 {
|
||||
csvString += "\n"
|
||||
csvString += String(dm.temperature.localeTemperature())
|
||||
|
|
@ -53,7 +53,7 @@ func TelemetryToCsvFile(telemetry: [TelemetryEntity], metricsType: Int) -> Strin
|
|||
return csvString
|
||||
}
|
||||
|
||||
func PositionToCsvFile(positions: [PositionEntity]) -> String {
|
||||
func positionToCsvFile(positions: [PositionEntity]) -> String {
|
||||
var csvString: String = ""
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,19 +7,19 @@
|
|||
import SwiftUI
|
||||
|
||||
class SwiftUIEmojiTextField: UITextField {
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
}
|
||||
|
||||
|
||||
func setEmoji() {
|
||||
_ = self.textInputMode
|
||||
}
|
||||
|
||||
|
||||
override var textInputContextIdentifier: String? {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
override var textInputMode: UITextInputMode? {
|
||||
for mode in UITextInputMode.activeInputModes {
|
||||
if mode.primaryLanguage == "emoji" {
|
||||
|
|
@ -34,7 +34,7 @@ class SwiftUIEmojiTextField: UITextField {
|
|||
struct EmojiOnlyTextField: UIViewRepresentable {
|
||||
@Binding var text: String
|
||||
var placeholder: String = ""
|
||||
|
||||
|
||||
func makeUIView(context: Context) -> SwiftUIEmojiTextField {
|
||||
let emojiTextField = SwiftUIEmojiTextField()
|
||||
emojiTextField.placeholder = placeholder
|
||||
|
|
@ -42,15 +42,15 @@ struct EmojiOnlyTextField: UIViewRepresentable {
|
|||
emojiTextField.delegate = context.coordinator
|
||||
return emojiTextField
|
||||
}
|
||||
|
||||
|
||||
func updateUIView(_ uiView: SwiftUIEmojiTextField, context: Context) {
|
||||
uiView.text = text
|
||||
}
|
||||
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
|
||||
class Coordinator: NSObject, UITextFieldDelegate {
|
||||
var parent: EmojiOnlyTextField
|
||||
init(parent: EmojiOnlyTextField) {
|
||||
|
|
@ -63,12 +63,3 @@ struct EmojiOnlyTextField: UIViewRepresentable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct EmojiContentView: View {
|
||||
//
|
||||
// @State private var text: String = ""
|
||||
//
|
||||
// var body: some View {
|
||||
// EmojiTextField(text: $text, placeholder: "Enter emoji")
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ extension Data {
|
|||
}
|
||||
var hexDescription: String {
|
||||
return reduce("") {$0 + String(format: "%02x", $1)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Date {
|
||||
|
|
@ -53,7 +53,7 @@ extension Float {
|
|||
let locale = NSLocale.current as NSLocale
|
||||
let localeUnit = locale.object(forKey: NSLocale.Key(rawValue: "kCFLocaleTemperatureUnitKey"))
|
||||
var format: UnitTemperature = .celsius
|
||||
|
||||
|
||||
if localeUnit! as! String == "Fahrenheit" {
|
||||
format = .fahrenheit
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ extension UIImage {
|
|||
}
|
||||
|
||||
extension String {
|
||||
|
||||
|
||||
func base64urlToBase64() -> String {
|
||||
var base64 = self
|
||||
.replacingOccurrences(of: "-", with: "+")
|
||||
|
|
@ -100,7 +100,7 @@ extension String {
|
|||
}
|
||||
return base64
|
||||
}
|
||||
|
||||
|
||||
func base64ToBase64url() -> String {
|
||||
let base64url = self
|
||||
.replacingOccurrences(of: "+", with: "-")
|
||||
|
|
@ -108,13 +108,12 @@ extension String {
|
|||
.replacingOccurrences(of: "=", with: "")
|
||||
return base64url
|
||||
}
|
||||
|
||||
|
||||
func onlyEmojis() -> Bool {
|
||||
return count > 0 && !contains { !$0.isEmoji }
|
||||
}
|
||||
|
||||
func image(fontSize:CGFloat = 40, bgColor:UIColor = UIColor.clear, imageSize:CGSize? = nil) -> UIImage?
|
||||
{
|
||||
|
||||
func image(fontSize: CGFloat = 40, bgColor: UIColor = UIColor.clear, imageSize: CGSize? = nil) -> UIImage? {
|
||||
let font = UIFont.systemFont(ofSize: fontSize)
|
||||
let attributes = [NSAttributedString.Key.font: font]
|
||||
let imageSize = imageSize ?? self.size(withAttributes: attributes)
|
||||
|
|
@ -127,7 +126,7 @@ extension String {
|
|||
UIGraphicsEndImageContext()
|
||||
return image
|
||||
}
|
||||
|
||||
|
||||
func camelCaseToWords() -> String {
|
||||
return unicodeScalars.dropFirst().reduce(String(prefix(1))) {
|
||||
return CharacterSet.uppercaseLetters.contains($1)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class LocationHelper: NSObject, ObservableObject {
|
|||
}
|
||||
return altitude
|
||||
}
|
||||
|
||||
|
||||
static var currentSpeed: CLLocationSpeed {
|
||||
|
||||
guard let speed = shared.locationManager.location?.speed else {
|
||||
|
|
@ -33,7 +33,7 @@ class LocationHelper: NSObject, ObservableObject {
|
|||
}
|
||||
return speed
|
||||
}
|
||||
|
||||
|
||||
static var currentHeading: CLLocationDirection {
|
||||
|
||||
guard let heading = shared.locationManager.location?.course else {
|
||||
|
|
@ -41,7 +41,7 @@ class LocationHelper: NSObject, ObservableObject {
|
|||
}
|
||||
return heading
|
||||
}
|
||||
|
||||
|
||||
static var currentTimestamp: Date {
|
||||
|
||||
guard let timestamp = shared.locationManager.location?.timestamp else {
|
||||
|
|
@ -49,21 +49,21 @@ class LocationHelper: NSObject, ObservableObject {
|
|||
}
|
||||
return timestamp
|
||||
}
|
||||
|
||||
|
||||
static var satsInView: Int {
|
||||
// If we have a position we have a sat
|
||||
var sats = 1
|
||||
if shared.locationManager.location?.verticalAccuracy ?? 0 > 0 {
|
||||
sats = 4
|
||||
if 0...5 ~= shared.locationManager.location?.horizontalAccuracy ?? 0{
|
||||
if 0...5 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
sats = 12
|
||||
} else if 6...15 ~= shared.locationManager.location?.horizontalAccuracy ?? 0{
|
||||
} else if 6...15 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
sats = 10
|
||||
} else if 16...30 ~= shared.locationManager.location?.horizontalAccuracy ?? 0{
|
||||
} else if 16...30 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
sats = 9
|
||||
} else if 31...45 ~= shared.locationManager.location?.horizontalAccuracy ?? 0{
|
||||
} else if 31...45 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
sats = 7
|
||||
} else if 46...60 ~= shared.locationManager.location?.horizontalAccuracy ?? 0{
|
||||
} else if 46...60 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
sats = 5
|
||||
}
|
||||
} else if shared.locationManager.location?.verticalAccuracy ?? 0 < 0 && 60...300 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class MeshLogger {
|
|||
}
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmssSSa", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mm:ss.SS a")
|
||||
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = dateFormatString
|
||||
let timestamp = formatter.string(from: Date())
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import ActivityKit
|
|||
#endif
|
||||
|
||||
func generateMessageMarkdown (message: String) -> String {
|
||||
|
||||
|
||||
let types: NSTextCheckingResult.CheckingType = [.address, .link, .phoneNumber]
|
||||
let detector = try! NSDataDetector(types: types.rawValue)
|
||||
let matches = detector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf16.count))
|
||||
var messageWithMarkdown = message
|
||||
if matches.count > 0 {
|
||||
|
||||
|
||||
for match in matches {
|
||||
guard let range = Range(match.range, in: message) else { continue }
|
||||
if match.resultType == .address {
|
||||
|
|
@ -39,8 +39,8 @@ func generateMessageMarkdown (message: String) -> String {
|
|||
return messageWithMarkdown
|
||||
}
|
||||
|
||||
func localConfig (config: Config, context:NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
// We don't care about any of the Power settings, config is available for everything else
|
||||
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
||||
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context)
|
||||
|
|
@ -57,8 +57,8 @@ func localConfig (config: Config, context:NSManagedObjectContext, nodeNum: Int64
|
|||
}
|
||||
}
|
||||
|
||||
func moduleConfig (config: ModuleConfig, context:NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(config.cannedMessage) {
|
||||
upsertCannedMessagesModuleConfigPacket(config: config.cannedMessage, nodeNum: nodeNum, context: context)
|
||||
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
|
||||
|
|
@ -75,18 +75,18 @@ func moduleConfig (config: ModuleConfig, context:NSManagedObjectContext, nodeNum
|
|||
}
|
||||
|
||||
func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedObjectContext) -> MyInfoEntity? {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.myinfo %@", comment: "MyInfo received: %@"), String(myInfo.myNodeNum))
|
||||
MeshLogger.log("ℹ️ \(logString)")
|
||||
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedMyInfo.isEmpty {
|
||||
|
||||
|
||||
let myInfoEntity = MyInfoEntity(context: context)
|
||||
myInfoEntity.peripheralId = peripheralId
|
||||
myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum)
|
||||
|
|
@ -111,19 +111,19 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
print("💥 Error Inserting New Core Data MyInfoEntity: \(nsError)")
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
fetchedMyInfo[0].peripheralId = peripheralId
|
||||
fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum)
|
||||
fetchedMyInfo[0].hasGps = myInfo.hasGps_p
|
||||
fetchedMyInfo[0].bitrate = myInfo.bitrate
|
||||
let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".")//.lastIndex(of: ".", offsetBy: -1)
|
||||
var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset:6, in: myInfo.firmwareVersion))]
|
||||
let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".")// .lastIndex(of: ".", offsetBy: -1)
|
||||
var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: myInfo.firmwareVersion))]
|
||||
version = version.dropLast()
|
||||
fetchedMyInfo[0].firmwareVersion = String(version)
|
||||
fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec)
|
||||
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
||||
fetchedMyInfo[0].maxChannels = Int32(bitPattern: myInfo.maxChannels)
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
|
||||
|
|
@ -141,17 +141,17 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
}
|
||||
|
||||
func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
|
||||
|
||||
|
||||
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.channel.received %d %@", comment: "Channel %d received from: %@"), channel.index, String(fromNum))
|
||||
MeshLogger.log("🎛️ \(logString)")
|
||||
|
||||
|
||||
let fetchedMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum)
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedMyInfo = try context.fetch(fetchedMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count == 1 {
|
||||
let newChannel = ChannelEntity(context: context)
|
||||
|
|
@ -190,16 +190,16 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
}
|
||||
|
||||
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if metadata.isInitialized {
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.device.metadata.received %@", comment: "Device Metadata admin message received from: %@"), String(fromNum))
|
||||
MeshLogger.log("🏷️ \(logString)")
|
||||
|
||||
|
||||
let fetchedNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchedNodeRequest.predicate = NSPredicate(format: "num == %lld", fromNum)
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchedNodeRequest) as! [NodeInfoEntity]
|
||||
if fetchedNode.count > 0 {
|
||||
let newMetadata = DeviceMetadataEntity(context: context)
|
||||
|
|
@ -229,26 +229,26 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
|
|||
}
|
||||
|
||||
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.nodeinfo.received %@", comment: "Node info received for: %@"), String(nodeInfo.num))
|
||||
MeshLogger.log("📟 \(logString)")
|
||||
|
||||
guard (nodeInfo.num > 0) else { return nil }
|
||||
|
||||
|
||||
guard nodeInfo.num > 0 else { return nil }
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Not Found Insert
|
||||
if fetchedNode.isEmpty && nodeInfo.hasUser {
|
||||
|
||||
|
||||
let newNode = NodeInfoEntity(context: context)
|
||||
newNode.id = Int64(nodeInfo.num)
|
||||
newNode.num = Int64(nodeInfo.num)
|
||||
newNode.channel = Int32(channel)
|
||||
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
telemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
|
|
@ -259,7 +259,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newTelemetries.append(telemetry)
|
||||
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
|
||||
}
|
||||
|
||||
|
||||
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
newNode.snr = nodeInfo.snr
|
||||
if nodeInfo.hasUser {
|
||||
|
|
@ -272,9 +272,8 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
newNode.user = newUser
|
||||
}
|
||||
|
||||
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000)
|
||||
{
|
||||
|
||||
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
||||
let position = PositionEntity(context: context)
|
||||
position.seqNo = Int32(nodeInfo.position.seqNumber)
|
||||
position.latitudeI = nodeInfo.position.latitudeI
|
||||
|
|
@ -288,13 +287,13 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newPostions.append(position)
|
||||
newNode.positions? = NSOrderedSet(array: newPostions)
|
||||
}
|
||||
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
newNode.myInfo = fetchedMyInfo[0]
|
||||
|
|
@ -311,15 +310,15 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
} else if nodeInfo.hasUser && nodeInfo.num > 0 {
|
||||
|
||||
|
||||
fetchedNode[0].id = Int64(nodeInfo.num)
|
||||
fetchedNode[0].num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
fetchedNode[0].snr = nodeInfo.snr
|
||||
fetchedNode[0].channel = Int32(channel)
|
||||
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
|
||||
fetchedNode[0].user!.userId = nodeInfo.user.id
|
||||
fetchedNode[0].user!.num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].user!.longName = nodeInfo.user.longName
|
||||
|
|
@ -327,9 +326,9 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
fetchedNode[0].user!.macaddr = nodeInfo.user.macaddr
|
||||
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
}
|
||||
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
|
||||
|
||||
let newTelemetry = TelemetryEntity(context: context)
|
||||
newTelemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
newTelemetry.voltage = nodeInfo.deviceMetrics.voltage
|
||||
|
|
@ -338,12 +337,11 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as! NSMutableOrderedSet
|
||||
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
|
||||
if nodeInfo.hasPosition {
|
||||
|
||||
|
||||
|
||||
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
||||
|
||||
|
||||
let position = PositionEntity(context: context)
|
||||
position.latitudeI = nodeInfo.position.latitudeI
|
||||
position.longitudeI = nodeInfo.position.longitudeI
|
||||
|
|
@ -353,13 +351,13 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
if fetchedMyInfo.count > 0 {
|
||||
|
|
@ -385,26 +383,26 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
}
|
||||
|
||||
func nodeInfoAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.nodeinfo.received %@", comment: "Node info received for: %@"), String(packet.from))
|
||||
MeshLogger.log("📟 \(logString)")
|
||||
|
||||
guard (packet.from > 0) else { return }
|
||||
|
||||
|
||||
guard packet.from > 0 else { return }
|
||||
|
||||
let fetchNodeInfoAppRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoAppRequest) as? [NodeInfoEntity] ?? []
|
||||
|
||||
|
||||
if fetchedNode.count == 1 {
|
||||
fetchedNode[0].id = Int64(packet.from)
|
||||
fetchedNode[0].num = Int64(packet.from)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime)))
|
||||
fetchedNode[0].snr = packet.rxSnr
|
||||
fetchedNode[0].channel = Int32(packet.channel)
|
||||
|
||||
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
if nodeInfoMessage.hasDeviceMetrics {
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
|
@ -442,21 +440,21 @@ func nodeInfoAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
}
|
||||
|
||||
func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
|
||||
|
||||
|
||||
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
if !cmmc.messages.isEmpty {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.cannedmessages.messages.received %@", comment: "Canned Messages Messages Received For: %@"), String(packet.from))
|
||||
MeshLogger.log("🥫 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedNode = try context.fetch(fetchNodeRequest) as! [NodeInfoEntity]
|
||||
if fetchedNode.count == 1 {
|
||||
|
|
@ -481,65 +479,65 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
}
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getChannelResponse(adminMessage.getChannelResponse) {
|
||||
channelPacket(channel: adminMessage.getChannelResponse, fromNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getDeviceMetadataResponse(adminMessage.getDeviceMetadataResponse) {
|
||||
deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) {
|
||||
|
||||
|
||||
let config = adminMessage.getConfigResponse
|
||||
|
||||
|
||||
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
||||
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
|
||||
upsertDeviceConfigPacket(config: config.device, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
|
||||
upsertLoRaConfigPacket(config: config.lora, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
|
||||
upsertNetworkConfigPacket(config: config.network, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
|
||||
upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
}
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) {
|
||||
|
||||
|
||||
let moduleConfig = adminMessage.getModuleConfigResponse
|
||||
|
||||
|
||||
if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfig.cannedMessage) {
|
||||
upsertCannedMessagesModuleConfigPacket(config: moduleConfig.cannedMessage, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfig.externalNotification) {
|
||||
upsertExternalNotificationModuleConfigPacket(config: moduleConfig.externalNotification, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(moduleConfig.mqtt) {
|
||||
upsertMqttModuleConfigPacket(config: moduleConfig.mqtt, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(moduleConfig.rangeTest) {
|
||||
upsertRangeTestModuleConfigPacket(config: moduleConfig.rangeTest, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(moduleConfig.serial) {
|
||||
upsertSerialModuleConfigPacket(config: moduleConfig.serial, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(moduleConfig.telemetry) {
|
||||
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
MeshLogger.log("🕸️ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())")
|
||||
}
|
||||
|
||||
|
||||
// Save an ack for the admin message log for each admin message response received as we stopped sending acks if there is also a response to reduce airtime.
|
||||
adminResponseAck(packet: packet, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let fetchedAdminMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
||||
fetchedAdminMessageRequest.predicate = NSPredicate(format: "messageId == %lld", packet.decoded.requestID)
|
||||
do {
|
||||
|
|
@ -565,22 +563,22 @@ func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
}
|
||||
|
||||
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
let routingError = RoutingError(rawValue: routingMessage.errorReason.rawValue)
|
||||
|
||||
|
||||
let routingErrorString = routingError?.display ?? NSLocalizedString("unknown", comment: "")
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.routing.message %@ %@", comment: "Routing received for RequestID: %@ Ack Status: %@"), String(packet.decoded.requestID), routingErrorString)
|
||||
MeshLogger.log("🕸️ \(logString)")
|
||||
|
||||
|
||||
let fetchMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
||||
fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedMessage = try context.fetch(fetchMessageRequest) as? [MessageEntity]
|
||||
if fetchedMessage?.count ?? 0 > 0 {
|
||||
|
||||
|
||||
if fetchedMessage![0].toUser != nil {
|
||||
// Real ACK from DM Recipient
|
||||
if packet.to != packet.from {
|
||||
|
|
@ -588,14 +586,14 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
}
|
||||
}
|
||||
fetchedMessage![0].ackError = Int32(routingMessage.errorReason.rawValue)
|
||||
|
||||
|
||||
if routingMessage.errorReason == Routing.Error.none {
|
||||
|
||||
|
||||
fetchedMessage![0].receivedACK = true
|
||||
}
|
||||
fetchedMessage![0].ackSNR = packet.rxSnr
|
||||
fetchedMessage![0].ackTimestamp = Int32(packet.rxTime)
|
||||
|
||||
|
||||
if fetchedMessage![0].toUser != nil {
|
||||
fetchedMessage![0].toUser?.objectWillChange.send()
|
||||
} else {
|
||||
|
|
@ -604,19 +602,19 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity]
|
||||
if fetchedMyInfo?.count ?? 0 > 0 {
|
||||
|
||||
|
||||
for ch in fetchedMyInfo![0].channels!.array as! [ChannelEntity] {
|
||||
|
||||
|
||||
if ch.index == packet.channel {
|
||||
ch.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
|
@ -631,25 +629,25 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
}
|
||||
|
||||
func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
// Only log telemetry from the mesh not the connected device
|
||||
if connectedNode != Int64(packet.from) {
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.received %@", comment: "Telemetry received for: %@"), String(packet.from))
|
||||
MeshLogger.log("📈 \(logString)")
|
||||
} else {
|
||||
// If it is the connected node
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
||||
|
||||
let fetchNodeTelemetryRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeTelemetryRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeTelemetryRequest) as! [NodeInfoEntity]
|
||||
if fetchedNode.count == 1 {
|
||||
if telemetryMessage.variant == Telemetry.OneOf_Variant.deviceMetrics(telemetryMessage.deviceMetrics) {
|
||||
|
|
@ -690,7 +688,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
content.body = "Time to charge your radio, there is \(telemetry.batteryLevel)% battery remaining."
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
||||
let uuidString = UUID().uuidString
|
||||
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
|
||||
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
|
||||
let notificationCenter = UNUserNotificationCenter.current()
|
||||
notificationCenter.add(request) { (error) in
|
||||
if error != nil {
|
||||
|
|
@ -710,12 +708,12 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
let updatedMeshStatus = MeshActivityAttributes.MeshActivityStatus(timerRange: date, connected: true, channelUtilization: telemetry.channelUtilization, airtime: telemetry.airUtilTx, batteryLevel: UInt32(telemetry.batteryLevel))
|
||||
let alertConfiguration = AlertConfiguration(title: "Mesh activity update", body: "Updated Device Metrics Data.", sound: .default)
|
||||
let updatedContent = ActivityContent(state: updatedMeshStatus, staleDate: nil)
|
||||
|
||||
|
||||
let meshActivity = Activity<MeshActivityAttributes>.activities.first(where: { $0.attributes.nodeNum == connectedNode })
|
||||
if meshActivity != nil {
|
||||
Task {
|
||||
await meshActivity?.update(updatedContent, alertConfiguration: alertConfiguration)
|
||||
//await meshActivity?.update(updatedContent)
|
||||
// await meshActivity?.update(updatedContent)
|
||||
print("Updated live activity.")
|
||||
}
|
||||
}
|
||||
|
|
@ -733,16 +731,16 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
}
|
||||
|
||||
func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) {
|
||||
|
||||
|
||||
MeshLogger.log("💬 \(NSLocalizedString("mesh.log.textmessage.received", comment: "Message received from the text message app"))")
|
||||
|
||||
|
||||
let messageUsers: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
||||
messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from])
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedUsers = try context.fetch(messageUsers) as! [UserEntity]
|
||||
let newMessage = MessageEntity(context: context)
|
||||
newMessage.messageId = Int64(packet.id)
|
||||
|
|
@ -751,11 +749,11 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
newMessage.snr = packet.rxSnr
|
||||
newMessage.isEmoji = packet.decoded.emoji == 1
|
||||
newMessage.channel = Int32(packet.channel)
|
||||
|
||||
|
||||
if packet.decoded.replyID > 0 {
|
||||
newMessage.replyID = Int64(packet.decoded.replyID)
|
||||
}
|
||||
|
||||
|
||||
if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != 4294967295 {
|
||||
newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to })
|
||||
}
|
||||
|
|
@ -764,20 +762,20 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
newMessage.messagePayload = messageText
|
||||
newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText)
|
||||
|
||||
|
||||
newMessage.fromUser?.objectWillChange.send()
|
||||
newMessage.toUser?.objectWillChange.send()
|
||||
|
||||
|
||||
var messageSaved = false
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
try context.save()
|
||||
print("💾 Saved a new message for \(newMessage.messageId)")
|
||||
messageSaved = true
|
||||
|
||||
|
||||
if messageSaved {
|
||||
|
||||
|
||||
if newMessage.fromUser != nil && newMessage.toUser != nil && !(newMessage.fromUser?.mute ?? false) {
|
||||
// Create an iOS Notification for the received DM message and schedule it immediately
|
||||
let manager = LocalNotificationManager()
|
||||
|
|
@ -791,17 +789,17 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
manager.schedule()
|
||||
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
} else if newMessage.fromUser != nil && newMessage.toUser == nil {
|
||||
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
|
||||
for channel in (fetchedMyInfo[0].channels?.array ?? []) as? [ChannelEntity] ?? [] {
|
||||
if channel.index == newMessage.channel {
|
||||
context.refresh(channel, mergeChanges: true)
|
||||
}
|
||||
|
||||
|
||||
if channel.index == newMessage.channel && !channel.mute {
|
||||
// Create an iOS Notification for the received private channel message and schedule it immediately
|
||||
let manager = LocalNotificationManager()
|
||||
|
|
@ -817,7 +815,7 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -833,21 +831,21 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
|
||||
func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.waypoint.received %@", comment: "Waypoint Packet received from node: %@"), String(packet.from))
|
||||
MeshLogger.log("📍 \(logString)")
|
||||
|
||||
|
||||
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")
|
||||
fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(packet.id))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
if let waypointMessage = try? Waypoint(serializedData: packet.decoded.payload) {
|
||||
|
||||
let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as! [WaypointEntity]
|
||||
if fetchedWaypoint.isEmpty {
|
||||
let waypoint = WaypointEntity(context: context)
|
||||
|
||||
|
||||
waypoint.id = Int64(packet.id)
|
||||
waypoint.name = waypointMessage.name
|
||||
waypoint.longDescription = waypointMessage.description_p
|
||||
|
|
@ -857,7 +855,7 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
waypoint.locked = Int64(waypointMessage.lockedTo)
|
||||
if waypointMessage.expire > 0 {
|
||||
waypoint.expire = Date(timeIntervalSince1970: TimeInterval(Int64(waypointMessage.expire)))
|
||||
}else {
|
||||
} else {
|
||||
waypoint.expire = nil
|
||||
}
|
||||
waypoint.created = Date()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import CoreData
|
|||
|
||||
@main
|
||||
struct MeshtasticAppleApp: App {
|
||||
|
||||
|
||||
let persistenceController = PersistenceController.shared
|
||||
@ObservedObject private var bleManager: BLEManager = BLEManager()
|
||||
@ObservedObject private var userSettings: UserSettings = UserSettings()
|
||||
|
|
@ -30,9 +30,9 @@ struct MeshtasticAppleApp: App {
|
|||
|
||||
print("URL received \(userActivity)")
|
||||
self.incomingUrl = userActivity.webpageURL
|
||||
|
||||
if ((self.incomingUrl?.absoluteString.lowercased().contains("meshtastic.org/e/#")) != nil) {
|
||||
|
||||
|
||||
if (self.incomingUrl?.absoluteString.lowercased().contains("meshtastic.org/e/#")) != nil {
|
||||
|
||||
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
|
||||
self.channelSettings = components.last!
|
||||
}
|
||||
|
|
@ -44,10 +44,10 @@ struct MeshtasticAppleApp: App {
|
|||
}
|
||||
}
|
||||
.onOpenURL(perform: { (url) in
|
||||
|
||||
|
||||
print("Some sort of URL was received \(url)")
|
||||
self.incomingUrl = url
|
||||
|
||||
|
||||
if url.absoluteString.lowercased().contains("meshtastic.org/e/#") {
|
||||
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
|
||||
self.channelSettings = components.last!
|
||||
|
|
@ -59,37 +59,37 @@ struct MeshtasticAppleApp: App {
|
|||
print("User wants to import a MBTILES offline map file: \(self.incomingUrl?.absoluteString ?? "No Tiles link")")
|
||||
}
|
||||
|
||||
//we are expecting a .mbtiles map file that contains raster data
|
||||
//save it to the documents directory, and name it offline_map.mbtiles
|
||||
// we are expecting a .mbtiles map file that contains raster data
|
||||
// save it to the documents directory, and name it offline_map.mbtiles
|
||||
let fileManager = FileManager.default
|
||||
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
let destination = documentsDirectory.appendingPathComponent("offline_map.mbtiles", isDirectory: false)
|
||||
|
||||
|
||||
if !self.saveChannels {
|
||||
|
||||
//tell the system we want the file please
|
||||
|
||||
// tell the system we want the file please
|
||||
guard url.startAccessingSecurityScopedResource() else {
|
||||
return
|
||||
}
|
||||
|
||||
//do we need to delete an old one?
|
||||
if (fileManager.fileExists(atPath: destination.path)) {
|
||||
|
||||
// do we need to delete an old one?
|
||||
if fileManager.fileExists(atPath: destination.path) {
|
||||
print("ℹ️ Found an old map file. Deleting it")
|
||||
try? fileManager.removeItem(atPath: destination.path)
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try fileManager.copyItem(at: url, to: destination)
|
||||
} catch {
|
||||
print("Copy MB Tile file failed. Error: \(error)")
|
||||
}
|
||||
|
||||
if (fileManager.fileExists(atPath: destination.path)) {
|
||||
|
||||
if fileManager.fileExists(atPath: destination.path) {
|
||||
print("ℹ️ Saved the map file")
|
||||
|
||||
//need to tell the map view that it needs to update and try loading the new overlay
|
||||
|
||||
// need to tell the map view that it needs to update and try loading the new overlay
|
||||
UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: "lastUpdatedLocalMapFile")
|
||||
|
||||
|
||||
} else {
|
||||
print("💥 Didn't save the map file")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,15 +23,13 @@ struct Peripheral: Identifiable {
|
|||
self.lastUpdate = lastUpdate
|
||||
self.peripheral = peripheral
|
||||
}
|
||||
|
||||
|
||||
func getSignalStrength() -> SignalStrength {
|
||||
if (NSNumber(value: rssi).compare(NSNumber(-65)) == ComparisonResult.orderedDescending) {
|
||||
if NSNumber(value: rssi).compare(NSNumber(-65)) == ComparisonResult.orderedDescending {
|
||||
return SignalStrength.strong
|
||||
}
|
||||
else if (NSNumber(value: rssi).compare(NSNumber(-85)) == ComparisonResult.orderedDescending) {
|
||||
} else if NSNumber(value: rssi).compare(NSNumber(-85)) == ComparisonResult.orderedDescending {
|
||||
return SignalStrength.normal
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return SignalStrength.weak
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class UserSettings: ObservableObject {
|
|||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
|
||||
self.meshtasticUsername = UserDefaults.standard.object(forKey: "meshtasticusername") as? String ?? ""
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
import Foundation
|
||||
|
||||
extension ChannelEntity {
|
||||
|
||||
|
||||
var allPrivateMessages: [MessageEntity] {
|
||||
|
||||
|
||||
self.value(forKey: "allPrivateMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,19 +32,19 @@ class PersistenceController {
|
|||
let container: NSPersistentContainer
|
||||
|
||||
init(inMemory: Bool = false) {
|
||||
|
||||
|
||||
container = NSPersistentContainer(name: "Meshtastic")
|
||||
|
||||
|
||||
if inMemory {
|
||||
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
|
||||
}
|
||||
|
||||
|
||||
container.loadPersistentStores(completionHandler: { (_, error) in
|
||||
|
||||
|
||||
// Merge policy that favors in memory data over data in the db
|
||||
self.container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
self.container.viewContext.automaticallyMergesChangesFromParent = true
|
||||
|
||||
|
||||
if let error = error as NSError? {
|
||||
|
||||
print("💥 CoreData Error: \(error.localizedDescription). Now attempting to truncate CoreData database. All app data will be lost.")
|
||||
|
|
@ -52,18 +52,18 @@ class PersistenceController {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
public func clearDatabase() {
|
||||
guard let url = self.container.persistentStoreDescriptions.first?.url else { return }
|
||||
|
||||
let persistentStoreCoordinator = self.container.persistentStoreCoordinator
|
||||
|
||||
do {
|
||||
|
||||
try persistentStoreCoordinator.destroyPersistentStore(at:url, ofType: NSSQLiteStoreType, options: nil)
|
||||
|
||||
try persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: NSSQLiteStoreType, options: nil)
|
||||
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
|
||||
print("💥 CoreData database truncated. All app data has been erased.")
|
||||
|
||||
|
||||
} catch let error {
|
||||
print("💣 Failed to destroy CoreData database, delete the app and re-install to clear data. Attempted to clear persistent store: " + error.localizedDescription)
|
||||
}
|
||||
|
|
@ -71,17 +71,17 @@ class PersistenceController {
|
|||
}
|
||||
|
||||
extension NSManagedObjectContext {
|
||||
|
||||
|
||||
/// Executes the given `NSBatchDeleteRequest` and directly merges the changes to bring the given managed object context up to date.
|
||||
///
|
||||
/// - Parameter batchDeleteRequest: The `NSBatchDeleteRequest` to execute.
|
||||
/// - Throws: An error if anything went wrong executing the batch deletion.
|
||||
public func executeAndMergeChanges(using batchDeleteRequest: NSBatchDeleteRequest) throws {
|
||||
batchDeleteRequest.resultType = .resultTypeObjectIDs
|
||||
|
||||
|
||||
let result = try execute(batchDeleteRequest) as? NSBatchDeleteResult
|
||||
let changes: [AnyHashable: Any] = [NSDeletedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
|
||||
|
||||
|
||||
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ extension PositionEntity {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var nodeLocation: CLLocation? {
|
||||
if latitudeI != 0 && longitudeI != 0 {
|
||||
let location = CLLocation(latitude: latitude!, longitude: longitude!)
|
||||
|
|
@ -40,7 +40,7 @@ extension PositionEntity {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var annotaton: MKPointAnnotation {
|
||||
let pointAnn = MKPointAnnotation()
|
||||
if nodeCoordinate != nil {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
import CoreData
|
||||
|
||||
public func getNodeInfo(id: Int64, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
|
||||
|
||||
|
||||
do {
|
||||
let fetchNodeInfo = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
if fetchNodeInfo.count == 1 {
|
||||
|
|
@ -24,10 +24,10 @@ public func getNodeInfo(id: Int64, context: NSManagedObjectContext) -> NodeInfoE
|
|||
}
|
||||
|
||||
public func getUser(id: Int64, context: NSManagedObjectContext) -> UserEntity {
|
||||
|
||||
|
||||
let fetchUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
||||
fetchUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedUser = try context.fetch(fetchUserRequest) as! [UserEntity]
|
||||
if fetchedUser.count == 1 {
|
||||
|
|
@ -40,10 +40,10 @@ public func getUser(id: Int64, context: NSManagedObjectContext) -> UserEntity {
|
|||
}
|
||||
|
||||
public func getWaypoint(id: Int64, context: NSManagedObjectContext) -> WaypointEntity {
|
||||
|
||||
|
||||
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")
|
||||
fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(id))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as! [WaypointEntity]
|
||||
if fetchedWaypoint.count == 1 {
|
||||
|
|
|
|||
|
|
@ -7,26 +7,26 @@
|
|||
import CoreData
|
||||
|
||||
public func clearPositions(destNum: Int64, context: NSManagedObjectContext) -> Bool {
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(destNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
|
||||
|
||||
let newPostions = [PositionEntity]()
|
||||
fetchedNode[0].positions? = NSOrderedSet(array: newPostions)
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
return true
|
||||
|
||||
|
||||
} catch {
|
||||
context.rollback()
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch NodeInfoEntity Error")
|
||||
return false
|
||||
|
|
@ -34,26 +34,26 @@ public func clearPositions(destNum: Int64, context: NSManagedObjectContext) -> B
|
|||
}
|
||||
|
||||
public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManagedObjectContext) -> Bool {
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(destNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
|
||||
|
||||
let emptyTelemetry = [TelemetryEntity]()
|
||||
fetchedNode[0].telemetries? = NSOrderedSet(array: emptyTelemetry)
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
return true
|
||||
|
||||
|
||||
} catch {
|
||||
context.rollback()
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
print("💥 Fetch NodeInfoEntity Error")
|
||||
return false
|
||||
|
|
@ -73,7 +73,7 @@ public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObje
|
|||
}
|
||||
|
||||
public func deleteUserMessages(user: UserEntity, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
do {
|
||||
let objects = user.messageList
|
||||
for object in objects {
|
||||
|
|
@ -86,13 +86,13 @@ public func deleteUserMessages(user: UserEntity, context: NSManagedObjectContext
|
|||
}
|
||||
|
||||
public func clearCoreDataDatabase(context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let persistenceController = PersistenceController.shared.container
|
||||
for i in 0...persistenceController.managedObjectModel.entities.count-1 {
|
||||
let entity = persistenceController.managedObjectModel.entities[i]
|
||||
let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
|
||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: query)
|
||||
|
||||
|
||||
do {
|
||||
try context.executeAndMergeChanges(using: deleteRequest)
|
||||
} catch let error as NSError {
|
||||
|
|
@ -102,23 +102,22 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext) {
|
|||
}
|
||||
|
||||
func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.position.received %@", comment: "Position Packet received from node: %@"), String(packet.from))
|
||||
MeshLogger.log("📍 \(logString)")
|
||||
|
||||
|
||||
let fetchNodePositionRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
if let positionMessage = try? Position(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
// Don't save empty position packets
|
||||
if positionMessage.longitudeI > 0 || positionMessage.latitudeI > 0 && (positionMessage.latitudeI != 373346000 && positionMessage.longitudeI != -1220090000)
|
||||
{
|
||||
if positionMessage.longitudeI > 0 || positionMessage.latitudeI > 0 && (positionMessage.latitudeI != 373346000 && positionMessage.longitudeI != -1220090000) {
|
||||
let fetchedNode = try context.fetch(fetchNodePositionRequest) as! [NodeInfoEntity]
|
||||
if fetchedNode.count == 1 {
|
||||
|
||||
|
||||
// Unset the current latest position for this node
|
||||
let fetchCurrentLatestPositionsRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "PositionEntity")
|
||||
fetchCurrentLatestPositionsRequest.predicate = NSPredicate(format: "nodePosition.num == %lld && latest = true", Int64(packet.from))
|
||||
|
|
@ -128,7 +127,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
position.latest = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let position = PositionEntity(context: context)
|
||||
position.latest = true
|
||||
position.snr = packet.rxSnr
|
||||
|
|
@ -145,14 +144,14 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
|
||||
}
|
||||
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
|
||||
|
||||
|
||||
mutablePositions.add(position)
|
||||
fetchedNode[0].id = Int64(packet.from)
|
||||
fetchedNode[0].num = Int64(packet.from)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
|
||||
fetchedNode[0].snr = packet.rxSnr
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated Node Position Coordinates, SNR and Time from Position App Packet For: \(fetchedNode[0].num)")
|
||||
|
|
@ -173,15 +172,15 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
}
|
||||
|
||||
func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.bluetooth.config %@", comment: "Bluetooth config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("📶 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save Device Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -214,14 +213,14 @@ func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, node
|
|||
}
|
||||
|
||||
func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.device.config %@", comment: "Device config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("📟 \(logString)")
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save Device Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -260,22 +259,22 @@ func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: I
|
|||
}
|
||||
|
||||
func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.display.config %@", comment: "Display config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🖥️ \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
|
||||
|
||||
// Found a node, save Device Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].displayConfig == nil {
|
||||
|
||||
|
||||
let newDisplayConfig = DisplayConfigEntity(context: context)
|
||||
newDisplayConfig.gpsFormat = Int32(config.gpsFormat.rawValue)
|
||||
newDisplayConfig.screenOnSeconds = Int32(config.screenOnSecs)
|
||||
|
|
@ -286,10 +285,9 @@ func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum:
|
|||
newDisplayConfig.displayMode = Int32(config.displaymode.rawValue)
|
||||
newDisplayConfig.headingBold = config.headingBold
|
||||
fetchedNode[0].displayConfig = newDisplayConfig
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
fetchedNode[0].displayConfig?.gpsFormat = Int32(config.gpsFormat.rawValue)
|
||||
fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.screenOnSecs)
|
||||
fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.autoScreenCarouselSecs)
|
||||
|
|
@ -299,41 +297,39 @@ func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum:
|
|||
fetchedNode[0].displayConfig?.displayMode = Int32(config.displaymode.rawValue)
|
||||
fetchedNode[0].displayConfig?.headingBold = config.headingBold
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
try context.save()
|
||||
print("💾 Updated Display Config for node number: \(String(nodeNum))")
|
||||
|
||||
|
||||
} catch {
|
||||
|
||||
|
||||
context.rollback()
|
||||
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Updating Core Data DisplayConfigEntity: \(nsError)")
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Display Config")
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Fetching node for core data DisplayConfigEntity failed: \(nsError)")
|
||||
}
|
||||
}
|
||||
|
||||
func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.lora.config %@", comment: "LoRa config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("📻 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", nodeNum)
|
||||
|
||||
do {
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save LoRa Config
|
||||
if fetchedNode.count > 0 {
|
||||
|
|
@ -388,15 +384,15 @@ func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64
|
|||
}
|
||||
|
||||
func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.network.config %@", comment: "Network config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🌐 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save WiFi Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -413,11 +409,11 @@ func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum:
|
|||
fetchedNode[0].networkConfig?.wifiSsid = config.wifiSsid
|
||||
fetchedNode[0].networkConfig?.wifiPsk = config.wifiPsk
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated Network Config for node number: \(String(nodeNum))")
|
||||
|
||||
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
|
|
@ -433,15 +429,15 @@ func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum:
|
|||
}
|
||||
|
||||
func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.position.config %@", comment: "Positon config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🗺️ \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save LoRa Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -482,24 +478,24 @@ func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNu
|
|||
}
|
||||
|
||||
func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.CannedMessageConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.cannedmessage.config %@", comment: "Canned Message module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🥫 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
|
||||
|
||||
// Found a node, save Canned Message Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].cannedMessageConfig == nil {
|
||||
|
||||
|
||||
let newCannedMessageConfig = CannedMessageConfigEntity(context: context)
|
||||
|
||||
|
||||
newCannedMessageConfig.enabled = config.enabled
|
||||
newCannedMessageConfig.sendBell = config.sendBell
|
||||
newCannedMessageConfig.rotary1Enabled = config.rotary1Enabled
|
||||
|
|
@ -510,11 +506,11 @@ func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.Cann
|
|||
newCannedMessageConfig.inputbrokerEventCw = Int32(config.inputbrokerEventCw.rawValue)
|
||||
newCannedMessageConfig.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue)
|
||||
newCannedMessageConfig.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue)
|
||||
|
||||
|
||||
fetchedNode[0].cannedMessageConfig = newCannedMessageConfig
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
fetchedNode[0].cannedMessageConfig?.enabled = config.enabled
|
||||
fetchedNode[0].cannedMessageConfig?.sendBell = config.sendBell
|
||||
fetchedNode[0].cannedMessageConfig?.rotary1Enabled = config.rotary1Enabled
|
||||
|
|
@ -526,7 +522,7 @@ func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.Cann
|
|||
fetchedNode[0].cannedMessageConfig?.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue)
|
||||
fetchedNode[0].cannedMessageConfig?.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue)
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated Canned Message Module Config for node number: \(String(nodeNum))")
|
||||
|
|
@ -545,19 +541,19 @@ func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.Cann
|
|||
}
|
||||
|
||||
func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.externalnotification.config %@", comment: "External Notifiation module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("📣 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save External Notificaitone Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].externalNotificationConfig == nil {
|
||||
let newExternalNotificationConfig = ExternalNotificationConfigEntity(context: context)
|
||||
newExternalNotificationConfig.enabled = config.enabled
|
||||
|
|
@ -575,7 +571,7 @@ func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfi
|
|||
newExternalNotificationConfig.outputMilliseconds = Int32(config.outputMs)
|
||||
newExternalNotificationConfig.nagTimeout = Int32(config.nagTimeout)
|
||||
fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig
|
||||
|
||||
|
||||
} else {
|
||||
fetchedNode[0].externalNotificationConfig?.enabled = config.enabled
|
||||
fetchedNode[0].externalNotificationConfig?.usePWM = config.usePwm
|
||||
|
|
@ -592,7 +588,7 @@ func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfi
|
|||
fetchedNode[0].externalNotificationConfig?.outputMilliseconds = Int32(config.outputMs)
|
||||
fetchedNode[0].externalNotificationConfig?.nagTimeout = Int32(config.nagTimeout)
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated External Notification Module Config for node number: \(String(nodeNum))")
|
||||
|
|
@ -611,19 +607,19 @@ func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfi
|
|||
}
|
||||
|
||||
func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.mqtt.config %@", comment: "MQTT module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🌉 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save MQTT Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].mqttConfig == nil {
|
||||
let newMQTTConfig = MQTTConfigEntity(context: context)
|
||||
newMQTTConfig.enabled = config.enabled
|
||||
|
|
@ -659,15 +655,15 @@ func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, no
|
|||
}
|
||||
|
||||
func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTestConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.rangetest.config %@", comment: "Range Test module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("⛰️ \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save Device Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -700,22 +696,22 @@ func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTest
|
|||
}
|
||||
|
||||
func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig, nodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.serial.config %@", comment: "Serial module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("🤖 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
|
||||
|
||||
// Found a node, save Device Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].serialConfig == nil {
|
||||
|
||||
|
||||
let newSerialConfig = SerialConfigEntity(context: context)
|
||||
newSerialConfig.enabled = config.enabled
|
||||
newSerialConfig.echo = config.echo
|
||||
|
|
@ -725,7 +721,7 @@ func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig
|
|||
newSerialConfig.timeout = Int32(config.timeout)
|
||||
newSerialConfig.mode = Int32(config.mode.rawValue)
|
||||
fetchedNode[0].serialConfig = newSerialConfig
|
||||
|
||||
|
||||
} else {
|
||||
fetchedNode[0].serialConfig?.enabled = config.enabled
|
||||
fetchedNode[0].serialConfig?.echo = config.echo
|
||||
|
|
@ -735,26 +731,26 @@ func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig
|
|||
fetchedNode[0].serialConfig?.timeout = Int32(config.timeout)
|
||||
fetchedNode[0].serialConfig?.mode = Int32(config.mode.rawValue)
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated Serial Module Config for node number: \(String(nodeNum))")
|
||||
|
||||
|
||||
} catch {
|
||||
|
||||
|
||||
context.rollback()
|
||||
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Updating Core Data SerialConfigEntity: \(nsError)")
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config")
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Fetching node for core data SerialConfigEntity failed: \(nsError)")
|
||||
}
|
||||
|
|
@ -764,51 +760,51 @@ func upsertTelemetryModuleConfigPacket(config: Meshtastic.ModuleConfig.Telemetry
|
|||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.config %@", comment: "Telemetry module config received: %@"), String(nodeNum))
|
||||
MeshLogger.log("📈 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save Telemetry Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
|
||||
if fetchedNode[0].telemetryConfig == nil {
|
||||
|
||||
|
||||
let newTelemetryConfig = TelemetryConfigEntity(context: context)
|
||||
|
||||
|
||||
newTelemetryConfig.deviceUpdateInterval = Int32(config.deviceUpdateInterval)
|
||||
newTelemetryConfig.environmentUpdateInterval = Int32(config.environmentUpdateInterval)
|
||||
newTelemetryConfig.environmentMeasurementEnabled = config.environmentMeasurementEnabled
|
||||
newTelemetryConfig.environmentScreenEnabled = config.environmentScreenEnabled
|
||||
newTelemetryConfig.environmentDisplayFahrenheit = config.environmentDisplayFahrenheit
|
||||
|
||||
|
||||
fetchedNode[0].telemetryConfig = newTelemetryConfig
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
fetchedNode[0].telemetryConfig?.deviceUpdateInterval = Int32(config.deviceUpdateInterval)
|
||||
fetchedNode[0].telemetryConfig?.environmentUpdateInterval = Int32(config.environmentUpdateInterval)
|
||||
fetchedNode[0].telemetryConfig?.environmentMeasurementEnabled = config.environmentMeasurementEnabled
|
||||
fetchedNode[0].telemetryConfig?.environmentScreenEnabled = config.environmentScreenEnabled
|
||||
fetchedNode[0].telemetryConfig?.environmentDisplayFahrenheit = config.environmentDisplayFahrenheit
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated Telemetry Module Config for node number: \(String(nodeNum))")
|
||||
|
||||
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Updating Core Data TelemetryConfigEntity: \(nsError)")
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Telemetry Module Config")
|
||||
}
|
||||
|
||||
|
||||
} catch {
|
||||
let nsError = error as NSError
|
||||
print("💥 Fetching node for core data TelemetryConfigEntity failed: \(nsError)")
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
import Foundation
|
||||
|
||||
extension UserEntity {
|
||||
|
||||
|
||||
var messageList: [MessageEntity] {
|
||||
|
||||
|
||||
self.value(forKey: "allMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
}
|
||||
|
||||
|
||||
var adminMessageList: [MessageEntity] {
|
||||
|
||||
|
||||
self.value(forKey: "adminMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ extension WaypointEntity {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var annotaton: MKPointAnnotation {
|
||||
let pointAnn = MKPointAnnotation()
|
||||
if waypointCoordinate != nil {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ struct AdminMessage {
|
|||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var payloadVariant: AdminMessage.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: AdminMessage.OneOf_PayloadVariant?
|
||||
|
||||
///
|
||||
/// Send the specified channel in the response to this message
|
||||
|
|
@ -752,7 +752,7 @@ extension AdminMessage.ConfigType: CaseIterable {
|
|||
.networkConfig,
|
||||
.displayConfig,
|
||||
.loraConfig,
|
||||
.bluetoothConfig,
|
||||
.bluetoothConfig
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -767,7 +767,7 @@ extension AdminMessage.ModuleConfigType: CaseIterable {
|
|||
.telemetryConfig,
|
||||
.cannedmsgConfig,
|
||||
.audioConfig,
|
||||
.remotehardwareConfig,
|
||||
.remotehardwareConfig
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -813,7 +813,7 @@ extension HamParameters: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".AdminMessage"
|
||||
|
|
@ -848,7 +848,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
97: .standard(proto: "reboot_seconds"),
|
||||
98: .standard(proto: "shutdown_seconds"),
|
||||
99: .standard(proto: "factory_reset"),
|
||||
100: .standard(proto: "nodedb_reset"),
|
||||
100: .standard(proto: "nodedb_reset")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1315,7 +1315,7 @@ extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding {
|
|||
3: .same(proto: "NETWORK_CONFIG"),
|
||||
4: .same(proto: "DISPLAY_CONFIG"),
|
||||
5: .same(proto: "LORA_CONFIG"),
|
||||
6: .same(proto: "BLUETOOTH_CONFIG"),
|
||||
6: .same(proto: "BLUETOOTH_CONFIG")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1329,7 +1329,7 @@ extension AdminMessage.ModuleConfigType: SwiftProtobuf._ProtoNameProviding {
|
|||
5: .same(proto: "TELEMETRY_CONFIG"),
|
||||
6: .same(proto: "CANNEDMSG_CONFIG"),
|
||||
7: .same(proto: "AUDIO_CONFIG"),
|
||||
8: .same(proto: "REMOTEHARDWARE_CONFIG"),
|
||||
8: .same(proto: "REMOTEHARDWARE_CONFIG")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1339,7 +1339,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
|
|||
1: .standard(proto: "call_sign"),
|
||||
2: .standard(proto: "tx_power"),
|
||||
3: .same(proto: "frequency"),
|
||||
4: .standard(proto: "short_name"),
|
||||
4: .standard(proto: "short_name")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ struct ChannelSet {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _loraConfig: Config.LoRaConfig? = nil
|
||||
fileprivate var _loraConfig: Config.LoRaConfig?
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
|
|
@ -59,13 +59,13 @@ extension ChannelSet: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".ChannelSet"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "settings"),
|
||||
2: .standard(proto: "lora_config"),
|
||||
2: .standard(proto: "lora_config")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -42,12 +42,12 @@ extension CannedMessageModuleConfig: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension CannedMessageModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".CannedMessageModuleConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "messages"),
|
||||
1: .same(proto: "messages")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ struct Channel {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _settings: ChannelSettings? = nil
|
||||
fileprivate var _settings: ChannelSettings?
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
|
@ -193,7 +193,7 @@ extension Channel.Role: CaseIterable {
|
|||
static var allCases: [Channel.Role] = [
|
||||
.disabled,
|
||||
.primary,
|
||||
.secondary,
|
||||
.secondary
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +207,7 @@ extension Channel.Role: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".ChannelSettings"
|
||||
|
|
@ -217,7 +217,7 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
|
|||
3: .same(proto: "name"),
|
||||
4: .same(proto: "id"),
|
||||
5: .standard(proto: "uplink_enabled"),
|
||||
6: .standard(proto: "downlink_enabled"),
|
||||
6: .standard(proto: "downlink_enabled")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -276,7 +276,7 @@ extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "index"),
|
||||
2: .same(proto: "settings"),
|
||||
3: .same(proto: "role"),
|
||||
3: .same(proto: "role")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -323,6 +323,6 @@ extension Channel.Role: SwiftProtobuf._ProtoNameProviding {
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "DISABLED"),
|
||||
1: .same(proto: "PRIMARY"),
|
||||
2: .same(proto: "SECONDARY"),
|
||||
2: .same(proto: "SECONDARY")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ struct Config {
|
|||
|
||||
///
|
||||
/// Payload Variant
|
||||
var payloadVariant: Config.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: Config.OneOf_PayloadVariant?
|
||||
|
||||
var device: Config.DeviceConfig {
|
||||
get {
|
||||
|
|
@ -632,7 +632,7 @@ struct Config {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _ipv4Config: Config.NetworkConfig.IpV4Config? = nil
|
||||
fileprivate var _ipv4Config: Config.NetworkConfig.IpV4Config?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -1252,7 +1252,7 @@ extension Config.DeviceConfig.Role: CaseIterable {
|
|||
.routerClient,
|
||||
.repeater,
|
||||
.tracker,
|
||||
.sensor,
|
||||
.sensor
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1261,7 +1261,7 @@ extension Config.DeviceConfig.RebroadcastMode: CaseIterable {
|
|||
static var allCases: [Config.DeviceConfig.RebroadcastMode] = [
|
||||
.all,
|
||||
.allSkipDecoding,
|
||||
.localOnly,
|
||||
.localOnly
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1278,7 +1278,7 @@ extension Config.PositionConfig.PositionFlags: CaseIterable {
|
|||
.seqNo,
|
||||
.timestamp,
|
||||
.heading,
|
||||
.speed,
|
||||
.speed
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1286,7 +1286,7 @@ extension Config.NetworkConfig.AddressMode: CaseIterable {
|
|||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.NetworkConfig.AddressMode] = [
|
||||
.dhcp,
|
||||
.static,
|
||||
.static
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1298,7 +1298,7 @@ extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable {
|
|||
.utm,
|
||||
.mgrs,
|
||||
.olc,
|
||||
.osgr,
|
||||
.osgr
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1306,7 +1306,7 @@ extension Config.DisplayConfig.DisplayUnits: CaseIterable {
|
|||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.DisplayConfig.DisplayUnits] = [
|
||||
.metric,
|
||||
.imperial,
|
||||
.imperial
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1316,7 +1316,7 @@ extension Config.DisplayConfig.OledType: CaseIterable {
|
|||
.oledAuto,
|
||||
.oledSsd1306,
|
||||
.oledSh1106,
|
||||
.oledSh1107,
|
||||
.oledSh1107
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1326,7 +1326,7 @@ extension Config.DisplayConfig.DisplayMode: CaseIterable {
|
|||
.default,
|
||||
.twocolor,
|
||||
.inverted,
|
||||
.color,
|
||||
.color
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1348,7 +1348,7 @@ extension Config.LoRaConfig.RegionCode: CaseIterable {
|
|||
.th,
|
||||
.lora24,
|
||||
.ua433,
|
||||
.ua868,
|
||||
.ua868
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1362,7 +1362,7 @@ extension Config.LoRaConfig.ModemPreset: CaseIterable {
|
|||
.mediumFast,
|
||||
.shortSlow,
|
||||
.shortFast,
|
||||
.longModerate,
|
||||
.longModerate
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1371,7 +1371,7 @@ extension Config.BluetoothConfig.PairingMode: CaseIterable {
|
|||
static var allCases: [Config.BluetoothConfig.PairingMode] = [
|
||||
.randomPin,
|
||||
.fixedPin,
|
||||
.noPin,
|
||||
.noPin
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1403,7 +1403,7 @@ extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".Config"
|
||||
|
|
@ -1414,7 +1414,7 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas
|
|||
4: .same(proto: "network"),
|
||||
5: .same(proto: "display"),
|
||||
6: .same(proto: "lora"),
|
||||
7: .same(proto: "bluetooth"),
|
||||
7: .same(proto: "bluetooth")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1574,7 +1574,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
|
|||
4: .standard(proto: "button_gpio"),
|
||||
5: .standard(proto: "buzzer_gpio"),
|
||||
6: .standard(proto: "rebroadcast_mode"),
|
||||
7: .standard(proto: "node_info_broadcast_secs"),
|
||||
7: .standard(proto: "node_info_broadcast_secs")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1641,7 +1641,7 @@ extension Config.DeviceConfig.Role: SwiftProtobuf._ProtoNameProviding {
|
|||
3: .same(proto: "ROUTER_CLIENT"),
|
||||
4: .same(proto: "REPEATER"),
|
||||
5: .same(proto: "TRACKER"),
|
||||
6: .same(proto: "SENSOR"),
|
||||
6: .same(proto: "SENSOR")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1649,7 +1649,7 @@ extension Config.DeviceConfig.RebroadcastMode: SwiftProtobuf._ProtoNameProviding
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "ALL"),
|
||||
1: .same(proto: "ALL_SKIP_DECODING"),
|
||||
2: .same(proto: "LOCAL_ONLY"),
|
||||
2: .same(proto: "LOCAL_ONLY")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1664,7 +1664,7 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
6: .standard(proto: "gps_attempt_time"),
|
||||
7: .standard(proto: "position_flags"),
|
||||
8: .standard(proto: "rx_gpio"),
|
||||
9: .standard(proto: "tx_gpio"),
|
||||
9: .standard(proto: "tx_gpio")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1745,7 +1745,7 @@ extension Config.PositionConfig.PositionFlags: SwiftProtobuf._ProtoNameProviding
|
|||
64: .same(proto: "SEQ_NO"),
|
||||
128: .same(proto: "TIMESTAMP"),
|
||||
256: .same(proto: "HEADING"),
|
||||
512: .same(proto: "SPEED"),
|
||||
512: .same(proto: "SPEED")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1759,7 +1759,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple
|
|||
5: .standard(proto: "mesh_sds_timeout_secs"),
|
||||
6: .standard(proto: "sds_secs"),
|
||||
7: .standard(proto: "ls_secs"),
|
||||
8: .standard(proto: "min_wake_secs"),
|
||||
8: .standard(proto: "min_wake_secs")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1833,7 +1833,7 @@ extension Config.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
6: .standard(proto: "eth_enabled"),
|
||||
7: .standard(proto: "address_mode"),
|
||||
8: .standard(proto: "ipv4_config"),
|
||||
9: .standard(proto: "rsyslog_server"),
|
||||
9: .standard(proto: "rsyslog_server")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1904,7 +1904,7 @@ extension Config.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
extension Config.NetworkConfig.AddressMode: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "DHCP"),
|
||||
1: .same(proto: "STATIC"),
|
||||
1: .same(proto: "STATIC")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1914,7 +1914,7 @@ extension Config.NetworkConfig.IpV4Config: SwiftProtobuf.Message, SwiftProtobuf.
|
|||
1: .same(proto: "ip"),
|
||||
2: .same(proto: "gateway"),
|
||||
3: .same(proto: "subnet"),
|
||||
4: .same(proto: "dns"),
|
||||
4: .same(proto: "dns")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1969,7 +1969,7 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
6: .same(proto: "units"),
|
||||
7: .same(proto: "oled"),
|
||||
8: .same(proto: "displaymode"),
|
||||
9: .standard(proto: "heading_bold"),
|
||||
9: .standard(proto: "heading_bold")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2045,14 +2045,14 @@ extension Config.DisplayConfig.GpsCoordinateFormat: SwiftProtobuf._ProtoNameProv
|
|||
2: .same(proto: "UTM"),
|
||||
3: .same(proto: "MGRS"),
|
||||
4: .same(proto: "OLC"),
|
||||
5: .same(proto: "OSGR"),
|
||||
5: .same(proto: "OSGR")
|
||||
]
|
||||
}
|
||||
|
||||
extension Config.DisplayConfig.DisplayUnits: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "METRIC"),
|
||||
1: .same(proto: "IMPERIAL"),
|
||||
1: .same(proto: "IMPERIAL")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2061,7 +2061,7 @@ extension Config.DisplayConfig.OledType: SwiftProtobuf._ProtoNameProviding {
|
|||
0: .same(proto: "OLED_AUTO"),
|
||||
1: .same(proto: "OLED_SSD1306"),
|
||||
2: .same(proto: "OLED_SH1106"),
|
||||
3: .same(proto: "OLED_SH1107"),
|
||||
3: .same(proto: "OLED_SH1107")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2070,7 +2070,7 @@ extension Config.DisplayConfig.DisplayMode: SwiftProtobuf._ProtoNameProviding {
|
|||
0: .same(proto: "DEFAULT"),
|
||||
1: .same(proto: "TWOCOLOR"),
|
||||
2: .same(proto: "INVERTED"),
|
||||
3: .same(proto: "COLOR"),
|
||||
3: .same(proto: "COLOR")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2091,7 +2091,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
|
|||
12: .standard(proto: "override_duty_cycle"),
|
||||
13: .standard(proto: "sx126x_rx_boosted_gain"),
|
||||
14: .standard(proto: "override_frequency"),
|
||||
103: .standard(proto: "ignore_incoming"),
|
||||
103: .standard(proto: "ignore_incoming")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2207,7 +2207,7 @@ extension Config.LoRaConfig.RegionCode: SwiftProtobuf._ProtoNameProviding {
|
|||
12: .same(proto: "TH"),
|
||||
13: .same(proto: "LORA_24"),
|
||||
14: .same(proto: "UA_433"),
|
||||
15: .same(proto: "UA_868"),
|
||||
15: .same(proto: "UA_868")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2220,7 +2220,7 @@ extension Config.LoRaConfig.ModemPreset: SwiftProtobuf._ProtoNameProviding {
|
|||
4: .same(proto: "MEDIUM_FAST"),
|
||||
5: .same(proto: "SHORT_SLOW"),
|
||||
6: .same(proto: "SHORT_FAST"),
|
||||
7: .same(proto: "LONG_MODERATE"),
|
||||
7: .same(proto: "LONG_MODERATE")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2229,7 +2229,7 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "enabled"),
|
||||
2: .same(proto: "mode"),
|
||||
3: .standard(proto: "fixed_pin"),
|
||||
3: .standard(proto: "fixed_pin")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2272,6 +2272,6 @@ extension Config.BluetoothConfig.PairingMode: SwiftProtobuf._ProtoNameProviding
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "RANDOM_PIN"),
|
||||
1: .same(proto: "FIXED_PIN"),
|
||||
2: .same(proto: "NO_PIN"),
|
||||
2: .same(proto: "NO_PIN")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -73,10 +73,10 @@ struct DeviceConnectionStatus {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _wifi: WifiConnectionStatus? = nil
|
||||
fileprivate var _ethernet: EthernetConnectionStatus? = nil
|
||||
fileprivate var _bluetooth: BluetoothConnectionStatus? = nil
|
||||
fileprivate var _serial: SerialConnectionStatus? = nil
|
||||
fileprivate var _wifi: WifiConnectionStatus?
|
||||
fileprivate var _ethernet: EthernetConnectionStatus?
|
||||
fileprivate var _bluetooth: BluetoothConnectionStatus?
|
||||
fileprivate var _serial: SerialConnectionStatus?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -109,7 +109,7 @@ struct WifiConnectionStatus {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _status: NetworkConnectionStatus? = nil
|
||||
fileprivate var _status: NetworkConnectionStatus?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -134,7 +134,7 @@ struct EthernetConnectionStatus {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _status: NetworkConnectionStatus? = nil
|
||||
fileprivate var _status: NetworkConnectionStatus?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -220,7 +220,7 @@ extension SerialConnectionStatus: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".DeviceConnectionStatus"
|
||||
|
|
@ -228,7 +228,7 @@ extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
|
|||
1: .same(proto: "wifi"),
|
||||
2: .same(proto: "ethernet"),
|
||||
3: .same(proto: "bluetooth"),
|
||||
4: .same(proto: "serial"),
|
||||
4: .same(proto: "serial")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -281,7 +281,7 @@ extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "status"),
|
||||
2: .same(proto: "ssid"),
|
||||
3: .same(proto: "rssi"),
|
||||
3: .same(proto: "rssi")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -327,7 +327,7 @@ extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
extension EthernetConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".EthernetConnectionStatus"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "status"),
|
||||
1: .same(proto: "status")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -366,7 +366,7 @@ extension NetworkConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
1: .standard(proto: "ip_address"),
|
||||
2: .standard(proto: "is_connected"),
|
||||
3: .standard(proto: "is_mqtt_connected"),
|
||||
4: .standard(proto: "is_syslog_connected"),
|
||||
4: .standard(proto: "is_syslog_connected")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -415,7 +415,7 @@ extension BluetoothConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "pin"),
|
||||
2: .same(proto: "rssi"),
|
||||
3: .standard(proto: "is_connected"),
|
||||
3: .standard(proto: "is_connected")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -458,7 +458,7 @@ extension SerialConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
|
|||
static let protoMessageName: String = _protobuf_package + ".SerialConnectionStatus"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "baud"),
|
||||
2: .standard(proto: "is_connected"),
|
||||
2: .standard(proto: "is_connected")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ extension ScreenFonts: CaseIterable {
|
|||
static var allCases: [ScreenFonts] = [
|
||||
.fontSmall,
|
||||
.fontMedium,
|
||||
.fontLarge,
|
||||
.fontLarge
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -246,8 +246,8 @@ struct OEMStore {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _oemLocalConfig: LocalConfig? = nil
|
||||
fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil
|
||||
fileprivate var _oemLocalConfig: LocalConfig?
|
||||
fileprivate var _oemLocalModuleConfig: LocalModuleConfig?
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
|
|
@ -259,13 +259,13 @@ extension OEMStore: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension ScreenFonts: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "FONT_SMALL"),
|
||||
1: .same(proto: "FONT_MEDIUM"),
|
||||
2: .same(proto: "FONT_LARGE"),
|
||||
2: .same(proto: "FONT_LARGE")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -279,16 +279,16 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
8: .same(proto: "version"),
|
||||
7: .standard(proto: "rx_text_message"),
|
||||
9: .standard(proto: "no_save"),
|
||||
11: .standard(proto: "did_gps_reset"),
|
||||
11: .standard(proto: "did_gps_reset")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _myNode: MyNodeInfo? = nil
|
||||
var _owner: User? = nil
|
||||
var _myNode: MyNodeInfo?
|
||||
var _owner: User?
|
||||
var _nodeDb: [NodeInfo] = []
|
||||
var _receiveQueue: [MeshPacket] = []
|
||||
var _version: UInt32 = 0
|
||||
var _rxTextMessage: MeshPacket? = nil
|
||||
var _rxTextMessage: MeshPacket?
|
||||
var _noSave: Bool = false
|
||||
var _didGpsReset: Bool = false
|
||||
|
||||
|
|
@ -397,7 +397,7 @@ extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
static let protoMessageName: String = _protobuf_package + ".ChannelFile"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "channels"),
|
||||
2: .same(proto: "version"),
|
||||
2: .same(proto: "version")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -441,7 +441,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
5: .standard(proto: "oem_text"),
|
||||
6: .standard(proto: "oem_aes_key"),
|
||||
7: .standard(proto: "oem_local_config"),
|
||||
8: .standard(proto: "oem_local_module_config"),
|
||||
8: .standard(proto: "oem_local_module_config")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ extension LocalModuleConfig: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".LocalConfig"
|
||||
|
|
@ -257,17 +257,17 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
5: .same(proto: "display"),
|
||||
6: .same(proto: "lora"),
|
||||
7: .same(proto: "bluetooth"),
|
||||
8: .same(proto: "version"),
|
||||
8: .same(proto: "version")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _device: Config.DeviceConfig? = nil
|
||||
var _position: Config.PositionConfig? = nil
|
||||
var _power: Config.PowerConfig? = nil
|
||||
var _network: Config.NetworkConfig? = nil
|
||||
var _display: Config.DisplayConfig? = nil
|
||||
var _lora: Config.LoRaConfig? = nil
|
||||
var _bluetooth: Config.BluetoothConfig? = nil
|
||||
var _device: Config.DeviceConfig?
|
||||
var _position: Config.PositionConfig?
|
||||
var _power: Config.PowerConfig?
|
||||
var _network: Config.NetworkConfig?
|
||||
var _display: Config.DisplayConfig?
|
||||
var _lora: Config.LoRaConfig?
|
||||
var _bluetooth: Config.BluetoothConfig?
|
||||
var _version: UInt32 = 0
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
|
@ -383,19 +383,19 @@ extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
|
|||
7: .standard(proto: "canned_message"),
|
||||
9: .same(proto: "audio"),
|
||||
10: .standard(proto: "remote_hardware"),
|
||||
8: .same(proto: "version"),
|
||||
8: .same(proto: "version")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _mqtt: ModuleConfig.MQTTConfig? = nil
|
||||
var _serial: ModuleConfig.SerialConfig? = nil
|
||||
var _externalNotification: ModuleConfig.ExternalNotificationConfig? = nil
|
||||
var _storeForward: ModuleConfig.StoreForwardConfig? = nil
|
||||
var _rangeTest: ModuleConfig.RangeTestConfig? = nil
|
||||
var _telemetry: ModuleConfig.TelemetryConfig? = nil
|
||||
var _cannedMessage: ModuleConfig.CannedMessageConfig? = nil
|
||||
var _audio: ModuleConfig.AudioConfig? = nil
|
||||
var _remoteHardware: ModuleConfig.RemoteHardwareConfig? = nil
|
||||
var _mqtt: ModuleConfig.MQTTConfig?
|
||||
var _serial: ModuleConfig.SerialConfig?
|
||||
var _externalNotification: ModuleConfig.ExternalNotificationConfig?
|
||||
var _storeForward: ModuleConfig.StoreForwardConfig?
|
||||
var _rangeTest: ModuleConfig.RangeTestConfig?
|
||||
var _telemetry: ModuleConfig.TelemetryConfig?
|
||||
var _cannedMessage: ModuleConfig.CannedMessageConfig?
|
||||
var _audio: ModuleConfig.AudioConfig?
|
||||
var _remoteHardware: ModuleConfig.RemoteHardwareConfig?
|
||||
var _version: UInt32 = 0
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -302,7 +302,7 @@ extension HardwareModel: CaseIterable {
|
|||
.heltecWslV3,
|
||||
.betafpv2400Tx,
|
||||
.betafpv900NanoTx,
|
||||
.privateHw,
|
||||
.privateHw
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +353,7 @@ extension Constants: CaseIterable {
|
|||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Constants] = [
|
||||
.zero,
|
||||
.dataPayloadLen,
|
||||
.dataPayloadLen
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -476,7 +476,7 @@ extension CriticalErrorCode: CaseIterable {
|
|||
.transmitFailed,
|
||||
.brownout,
|
||||
.sx1262Failure,
|
||||
.radioSpiBug,
|
||||
.radioSpiBug
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -781,7 +781,7 @@ extension Position.LocSource: CaseIterable {
|
|||
.locUnset,
|
||||
.locManual,
|
||||
.locInternal,
|
||||
.locExternal,
|
||||
.locExternal
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -792,7 +792,7 @@ extension Position.AltSource: CaseIterable {
|
|||
.altManual,
|
||||
.altInternal,
|
||||
.altExternal,
|
||||
.altBarometric,
|
||||
.altBarometric
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -886,7 +886,7 @@ struct Routing {
|
|||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var variant: Routing.OneOf_Variant? = nil
|
||||
var variant: Routing.OneOf_Variant?
|
||||
|
||||
///
|
||||
/// A route request going from the requester
|
||||
|
|
@ -1075,7 +1075,7 @@ extension Routing.Error: CaseIterable {
|
|||
.noResponse,
|
||||
.dutyCycleLimit,
|
||||
.badRequest,
|
||||
.notAuthorized,
|
||||
.notAuthorized
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1503,7 +1503,7 @@ extension MeshPacket.Priority: CaseIterable {
|
|||
.default,
|
||||
.reliable,
|
||||
.ack,
|
||||
.max,
|
||||
.max
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1512,7 +1512,7 @@ extension MeshPacket.Delayed: CaseIterable {
|
|||
static var allCases: [MeshPacket.Delayed] = [
|
||||
.noDelay,
|
||||
.broadcast,
|
||||
.direct,
|
||||
.direct
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1591,9 +1591,9 @@ struct NodeInfo {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _user: User? = nil
|
||||
fileprivate var _position: Position? = nil
|
||||
fileprivate var _deviceMetrics: DeviceMetrics? = nil
|
||||
fileprivate var _user: User?
|
||||
fileprivate var _position: Position?
|
||||
fileprivate var _deviceMetrics: DeviceMetrics?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -1796,7 +1796,7 @@ extension LogRecord.Level: CaseIterable {
|
|||
.warning,
|
||||
.info,
|
||||
.debug,
|
||||
.trace,
|
||||
.trace
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2102,7 +2102,7 @@ struct ToRadio {
|
|||
|
||||
///
|
||||
/// Log levels, chosen to match python logging conventions.
|
||||
var payloadVariant: ToRadio.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: ToRadio.OneOf_PayloadVariant?
|
||||
|
||||
///
|
||||
/// Send this packet on the mesh
|
||||
|
|
@ -2308,7 +2308,7 @@ extension DeviceMetadata: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
|
@ -2346,14 +2346,14 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
44: .same(proto: "HELTEC_WSL_V3"),
|
||||
45: .same(proto: "BETAFPV_2400_TX"),
|
||||
46: .same(proto: "BETAFPV_900_NANO_TX"),
|
||||
255: .same(proto: "PRIVATE_HW"),
|
||||
255: .same(proto: "PRIVATE_HW")
|
||||
]
|
||||
}
|
||||
|
||||
extension Constants: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "ZERO"),
|
||||
237: .same(proto: "DATA_PAYLOAD_LEN"),
|
||||
237: .same(proto: "DATA_PAYLOAD_LEN")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2370,7 +2370,7 @@ extension CriticalErrorCode: SwiftProtobuf._ProtoNameProviding {
|
|||
8: .same(proto: "TRANSMIT_FAILED"),
|
||||
9: .same(proto: "BROWNOUT"),
|
||||
10: .same(proto: "SX1262_FAILURE"),
|
||||
11: .same(proto: "RADIO_SPI_BUG"),
|
||||
11: .same(proto: "RADIO_SPI_BUG")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2398,7 +2398,7 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
19: .standard(proto: "sats_in_view"),
|
||||
20: .standard(proto: "sensor_id"),
|
||||
21: .standard(proto: "next_update"),
|
||||
22: .standard(proto: "seq_number"),
|
||||
22: .standard(proto: "seq_number")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -2611,7 +2611,7 @@ extension Position.LocSource: SwiftProtobuf._ProtoNameProviding {
|
|||
0: .same(proto: "LOC_UNSET"),
|
||||
1: .same(proto: "LOC_MANUAL"),
|
||||
2: .same(proto: "LOC_INTERNAL"),
|
||||
3: .same(proto: "LOC_EXTERNAL"),
|
||||
3: .same(proto: "LOC_EXTERNAL")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2621,7 +2621,7 @@ extension Position.AltSource: SwiftProtobuf._ProtoNameProviding {
|
|||
1: .same(proto: "ALT_MANUAL"),
|
||||
2: .same(proto: "ALT_INTERNAL"),
|
||||
3: .same(proto: "ALT_EXTERNAL"),
|
||||
4: .same(proto: "ALT_BAROMETRIC"),
|
||||
4: .same(proto: "ALT_BAROMETRIC")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2633,7 +2633,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
|
|||
3: .standard(proto: "short_name"),
|
||||
4: .same(proto: "macaddr"),
|
||||
5: .standard(proto: "hw_model"),
|
||||
6: .standard(proto: "is_licensed"),
|
||||
6: .standard(proto: "is_licensed")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2690,7 +2690,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
|
|||
extension RouteDiscovery: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".RouteDiscovery"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "route"),
|
||||
1: .same(proto: "route")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2724,7 +2724,7 @@ extension Routing: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "route_request"),
|
||||
2: .standard(proto: "route_reply"),
|
||||
3: .standard(proto: "error_reason"),
|
||||
3: .standard(proto: "error_reason")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2815,7 +2815,7 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding {
|
|||
8: .same(proto: "NO_RESPONSE"),
|
||||
9: .same(proto: "DUTY_CYCLE_LIMIT"),
|
||||
32: .same(proto: "BAD_REQUEST"),
|
||||
33: .same(proto: "NOT_AUTHORIZED"),
|
||||
33: .same(proto: "NOT_AUTHORIZED")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2829,7 +2829,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
5: .same(proto: "source"),
|
||||
6: .standard(proto: "request_id"),
|
||||
7: .standard(proto: "reply_id"),
|
||||
8: .same(proto: "emoji"),
|
||||
8: .same(proto: "emoji")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2903,7 +2903,7 @@ extension Waypoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
5: .standard(proto: "locked_to"),
|
||||
6: .same(proto: "name"),
|
||||
7: .same(proto: "description"),
|
||||
8: .same(proto: "icon"),
|
||||
8: .same(proto: "icon")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2982,7 +2982,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
10: .standard(proto: "want_ack"),
|
||||
11: .same(proto: "priority"),
|
||||
12: .standard(proto: "rx_rssi"),
|
||||
13: .same(proto: "delayed"),
|
||||
13: .same(proto: "delayed")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -3160,7 +3160,7 @@ extension MeshPacket.Priority: SwiftProtobuf._ProtoNameProviding {
|
|||
64: .same(proto: "DEFAULT"),
|
||||
70: .same(proto: "RELIABLE"),
|
||||
120: .same(proto: "ACK"),
|
||||
127: .same(proto: "MAX"),
|
||||
127: .same(proto: "MAX")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -3168,7 +3168,7 @@ extension MeshPacket.Delayed: SwiftProtobuf._ProtoNameProviding {
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "NO_DELAY"),
|
||||
1: .same(proto: "DELAYED_BROADCAST"),
|
||||
2: .same(proto: "DELAYED_DIRECT"),
|
||||
2: .same(proto: "DELAYED_DIRECT")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -3180,7 +3180,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
3: .same(proto: "position"),
|
||||
4: .same(proto: "snr"),
|
||||
5: .standard(proto: "last_heard"),
|
||||
6: .standard(proto: "device_metrics"),
|
||||
6: .standard(proto: "device_metrics")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3256,7 +3256,7 @@ extension MyNodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
13: .standard(proto: "air_period_rx"),
|
||||
14: .standard(proto: "has_wifi"),
|
||||
15: .standard(proto: "channel_utilization"),
|
||||
16: .standard(proto: "air_util_tx"),
|
||||
16: .standard(proto: "air_util_tx")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3366,7 +3366,7 @@ extension LogRecord: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
1: .same(proto: "message"),
|
||||
2: .same(proto: "time"),
|
||||
3: .same(proto: "source"),
|
||||
4: .same(proto: "level"),
|
||||
4: .same(proto: "level")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3418,7 +3418,7 @@ extension LogRecord.Level: SwiftProtobuf._ProtoNameProviding {
|
|||
20: .same(proto: "INFO"),
|
||||
30: .same(proto: "WARNING"),
|
||||
40: .same(proto: "ERROR"),
|
||||
50: .same(proto: "CRITICAL"),
|
||||
50: .same(proto: "CRITICAL")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -3428,7 +3428,7 @@ extension QueueStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
1: .same(proto: "res"),
|
||||
2: .same(proto: "free"),
|
||||
3: .same(proto: "maxlen"),
|
||||
4: .standard(proto: "mesh_packet_id"),
|
||||
4: .standard(proto: "mesh_packet_id")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3487,7 +3487,7 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
10: .same(proto: "channel"),
|
||||
11: .same(proto: "queueStatus"),
|
||||
12: .same(proto: "xmodemPacket"),
|
||||
13: .same(proto: "metadata"),
|
||||
13: .same(proto: "metadata")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -3758,7 +3758,7 @@ extension ToRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
1: .same(proto: "packet"),
|
||||
3: .standard(proto: "want_config_id"),
|
||||
4: .same(proto: "disconnect"),
|
||||
5: .same(proto: "xmodemPacket"),
|
||||
5: .same(proto: "xmodemPacket")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3852,7 +3852,7 @@ extension Compressed: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
static let protoMessageName: String = _protobuf_package + ".Compressed"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "portnum"),
|
||||
2: .same(proto: "data"),
|
||||
2: .same(proto: "data")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3897,7 +3897,7 @@ extension DeviceMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
|
|||
6: .same(proto: "hasEthernet"),
|
||||
7: .same(proto: "role"),
|
||||
8: .standard(proto: "position_flags"),
|
||||
9: .standard(proto: "hw_model"),
|
||||
9: .standard(proto: "hw_model")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ struct ModuleConfig {
|
|||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var payloadVariant: ModuleConfig.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: ModuleConfig.OneOf_PayloadVariant?
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
|
|
@ -829,7 +829,7 @@ extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable {
|
|||
.codec21300,
|
||||
.codec21200,
|
||||
.codec2700,
|
||||
.codec2700B,
|
||||
.codec2700B
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -851,7 +851,7 @@ extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable {
|
|||
.baud230400,
|
||||
.baud460800,
|
||||
.baud576000,
|
||||
.baud921600,
|
||||
.baud921600
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +862,7 @@ extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable {
|
|||
.simple,
|
||||
.proto,
|
||||
.textmsg,
|
||||
.nmea,
|
||||
.nmea
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -876,7 +876,7 @@ extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable {
|
|||
.right,
|
||||
.select,
|
||||
.back,
|
||||
.cancel,
|
||||
.cancel
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -902,7 +902,7 @@ extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension ModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".ModuleConfig"
|
||||
|
|
@ -915,7 +915,7 @@ extension ModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
6: .same(proto: "telemetry"),
|
||||
7: .standard(proto: "canned_message"),
|
||||
8: .same(proto: "audio"),
|
||||
9: .standard(proto: "remote_hardware"),
|
||||
9: .standard(proto: "remote_hardware")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1108,7 +1108,7 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
3: .same(proto: "username"),
|
||||
4: .same(proto: "password"),
|
||||
5: .standard(proto: "encryption_enabled"),
|
||||
6: .standard(proto: "json_enabled"),
|
||||
6: .standard(proto: "json_enabled")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1165,7 +1165,7 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
extension ModuleConfig.RemoteHardwareConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = ModuleConfig.protoMessageName + ".RemoteHardwareConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "enabled"),
|
||||
1: .same(proto: "enabled")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1203,7 +1203,7 @@ extension ModuleConfig.AudioConfig: SwiftProtobuf.Message, SwiftProtobuf._Messag
|
|||
4: .standard(proto: "i2s_ws"),
|
||||
5: .standard(proto: "i2s_sd"),
|
||||
6: .standard(proto: "i2s_din"),
|
||||
7: .standard(proto: "i2s_sck"),
|
||||
7: .standard(proto: "i2s_sck")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1272,7 +1272,7 @@ extension ModuleConfig.AudioConfig.Audio_Baud: SwiftProtobuf._ProtoNameProviding
|
|||
5: .same(proto: "CODEC2_1300"),
|
||||
6: .same(proto: "CODEC2_1200"),
|
||||
7: .same(proto: "CODEC2_700"),
|
||||
8: .same(proto: "CODEC2_700B"),
|
||||
8: .same(proto: "CODEC2_700B")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1285,7 +1285,7 @@ extension ModuleConfig.SerialConfig: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
4: .same(proto: "txd"),
|
||||
5: .same(proto: "baud"),
|
||||
6: .same(proto: "timeout"),
|
||||
7: .same(proto: "mode"),
|
||||
7: .same(proto: "mode")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1361,7 +1361,7 @@ extension ModuleConfig.SerialConfig.Serial_Baud: SwiftProtobuf._ProtoNameProvidi
|
|||
12: .same(proto: "BAUD_230400"),
|
||||
13: .same(proto: "BAUD_460800"),
|
||||
14: .same(proto: "BAUD_576000"),
|
||||
15: .same(proto: "BAUD_921600"),
|
||||
15: .same(proto: "BAUD_921600")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1371,7 +1371,7 @@ extension ModuleConfig.SerialConfig.Serial_Mode: SwiftProtobuf._ProtoNameProvidi
|
|||
1: .same(proto: "SIMPLE"),
|
||||
2: .same(proto: "PROTO"),
|
||||
3: .same(proto: "TEXTMSG"),
|
||||
4: .same(proto: "NMEA"),
|
||||
4: .same(proto: "NMEA")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1391,7 +1391,7 @@ extension ModuleConfig.ExternalNotificationConfig: SwiftProtobuf.Message, SwiftP
|
|||
12: .standard(proto: "alert_bell_vibra"),
|
||||
13: .standard(proto: "alert_bell_buzzer"),
|
||||
7: .standard(proto: "use_pwm"),
|
||||
14: .standard(proto: "nag_timeout"),
|
||||
14: .standard(proto: "nag_timeout")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1492,7 +1492,7 @@ extension ModuleConfig.StoreForwardConfig: SwiftProtobuf.Message, SwiftProtobuf.
|
|||
2: .same(proto: "heartbeat"),
|
||||
3: .same(proto: "records"),
|
||||
4: .standard(proto: "history_return_max"),
|
||||
5: .standard(proto: "history_return_window"),
|
||||
5: .standard(proto: "history_return_window")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1546,7 +1546,7 @@ extension ModuleConfig.RangeTestConfig: SwiftProtobuf.Message, SwiftProtobuf._Me
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "enabled"),
|
||||
2: .same(proto: "sender"),
|
||||
3: .same(proto: "save"),
|
||||
3: .same(proto: "save")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1594,7 +1594,7 @@ extension ModuleConfig.TelemetryConfig: SwiftProtobuf.Message, SwiftProtobuf._Me
|
|||
4: .standard(proto: "environment_screen_enabled"),
|
||||
5: .standard(proto: "environment_display_fahrenheit"),
|
||||
6: .standard(proto: "air_quality_enabled"),
|
||||
7: .standard(proto: "air_quality_interval"),
|
||||
7: .standard(proto: "air_quality_interval")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1666,7 +1666,7 @@ extension ModuleConfig.CannedMessageConfig: SwiftProtobuf.Message, SwiftProtobuf
|
|||
8: .standard(proto: "updown1_enabled"),
|
||||
9: .same(proto: "enabled"),
|
||||
10: .standard(proto: "allow_input_source"),
|
||||
11: .standard(proto: "send_bell"),
|
||||
11: .standard(proto: "send_bell")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1754,6 +1754,6 @@ extension ModuleConfig.CannedMessageConfig.InputEventChar: SwiftProtobuf._ProtoN
|
|||
19: .same(proto: "LEFT"),
|
||||
20: .same(proto: "RIGHT"),
|
||||
24: .same(proto: "CANCEL"),
|
||||
27: .same(proto: "BACK"),
|
||||
27: .same(proto: "BACK")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ struct ServiceEnvelope {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _packet: MeshPacket? = nil
|
||||
fileprivate var _packet: MeshPacket?
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
|
|
@ -61,14 +61,14 @@ extension ServiceEnvelope: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".ServiceEnvelope"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "packet"),
|
||||
2: .standard(proto: "channel_id"),
|
||||
3: .standard(proto: "gateway_id"),
|
||||
3: .standard(proto: "gateway_id")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ extension PortNum: CaseIterable {
|
|||
.tracerouteApp,
|
||||
.privateApp,
|
||||
.atakForwarder,
|
||||
.max,
|
||||
.max
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -273,6 +273,6 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding {
|
|||
70: .same(proto: "TRACEROUTE_APP"),
|
||||
256: .same(proto: "PRIVATE_APP"),
|
||||
257: .same(proto: "ATAK_FORWARDER"),
|
||||
511: .same(proto: "MAX"),
|
||||
511: .same(proto: "MAX")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ extension HardwareMessage.TypeEnum: CaseIterable {
|
|||
.watchGpios,
|
||||
.gpiosChanged,
|
||||
.readGpios,
|
||||
.readGpiosReply,
|
||||
.readGpiosReply
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -138,14 +138,14 @@ extension HardwareMessage.TypeEnum: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension HardwareMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".HardwareMessage"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "type"),
|
||||
2: .standard(proto: "gpio_mask"),
|
||||
3: .standard(proto: "gpio_value"),
|
||||
3: .standard(proto: "gpio_value")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -191,6 +191,6 @@ extension HardwareMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding {
|
|||
2: .same(proto: "WATCH_GPIOS"),
|
||||
3: .same(proto: "GPIOS_CHANGED"),
|
||||
4: .same(proto: "READ_GPIOS"),
|
||||
5: .same(proto: "READ_GPIOS_REPLY"),
|
||||
5: .same(proto: "READ_GPIOS_REPLY")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -42,12 +42,12 @@ extension RTTTLConfig: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension RTTTLConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".RTTTLConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "ringtone"),
|
||||
1: .same(proto: "ringtone")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ struct StoreAndForward {
|
|||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var variant: StoreAndForward.OneOf_Variant? = nil
|
||||
var variant: StoreAndForward.OneOf_Variant?
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
|
|
@ -345,7 +345,7 @@ extension StoreAndForward.RequestResponse: CaseIterable {
|
|||
.clientStats,
|
||||
.clientPing,
|
||||
.clientPong,
|
||||
.clientAbort,
|
||||
.clientAbort
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -362,7 +362,7 @@ extension StoreAndForward.Heartbeat: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension StoreAndForward: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".StoreAndForward"
|
||||
|
|
@ -371,7 +371,7 @@ extension StoreAndForward: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
|
|||
2: .same(proto: "stats"),
|
||||
3: .same(proto: "history"),
|
||||
4: .same(proto: "heartbeat"),
|
||||
5: .same(proto: "empty"),
|
||||
5: .same(proto: "empty")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -486,7 +486,7 @@ extension StoreAndForward.RequestResponse: SwiftProtobuf._ProtoNameProviding {
|
|||
66: .same(proto: "CLIENT_STATS"),
|
||||
67: .same(proto: "CLIENT_PING"),
|
||||
68: .same(proto: "CLIENT_PONG"),
|
||||
106: .same(proto: "CLIENT_ABORT"),
|
||||
106: .same(proto: "CLIENT_ABORT")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -501,7 +501,7 @@ extension StoreAndForward.Statistics: SwiftProtobuf.Message, SwiftProtobuf._Mess
|
|||
6: .standard(proto: "requests_history"),
|
||||
7: .same(proto: "heartbeat"),
|
||||
8: .standard(proto: "return_max"),
|
||||
9: .standard(proto: "return_window"),
|
||||
9: .standard(proto: "return_window")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -575,7 +575,7 @@ extension StoreAndForward.History: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "history_messages"),
|
||||
2: .same(proto: "window"),
|
||||
3: .standard(proto: "last_request"),
|
||||
3: .standard(proto: "last_request")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -618,7 +618,7 @@ extension StoreAndForward.Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
static let protoMessageName: String = StoreAndForward.protoMessageName + ".Heartbeat"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "period"),
|
||||
2: .same(proto: "secondary"),
|
||||
2: .same(proto: "secondary")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ extension TelemetrySensorType: CaseIterable {
|
|||
.qmi8658,
|
||||
.qmc5883L,
|
||||
.sht31,
|
||||
.pmsa003I,
|
||||
.pmsa003I
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -291,7 +291,7 @@ struct Telemetry {
|
|||
/// seconds since 1970
|
||||
var time: UInt32 = 0
|
||||
|
||||
var variant: Telemetry.OneOf_Variant? = nil
|
||||
var variant: Telemetry.OneOf_Variant?
|
||||
|
||||
///
|
||||
/// Key native device metrics such as battery level
|
||||
|
|
@ -374,7 +374,7 @@ extension Telemetry.OneOf_Variant: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
|
@ -391,7 +391,7 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding {
|
|||
10: .same(proto: "QMI8658"),
|
||||
11: .same(proto: "QMC5883L"),
|
||||
12: .same(proto: "SHT31"),
|
||||
13: .same(proto: "PMSA003I"),
|
||||
13: .same(proto: "PMSA003I")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
|
|||
1: .standard(proto: "battery_level"),
|
||||
2: .same(proto: "voltage"),
|
||||
3: .standard(proto: "channel_utilization"),
|
||||
4: .standard(proto: "air_util_tx"),
|
||||
4: .standard(proto: "air_util_tx")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -453,7 +453,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple
|
|||
3: .standard(proto: "barometric_pressure"),
|
||||
4: .standard(proto: "gas_resistance"),
|
||||
5: .same(proto: "voltage"),
|
||||
6: .same(proto: "current"),
|
||||
6: .same(proto: "current")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -521,7 +521,7 @@ extension AirQualityMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
|
|||
9: .standard(proto: "particles_10um"),
|
||||
10: .standard(proto: "particles_25um"),
|
||||
11: .standard(proto: "particles_50um"),
|
||||
12: .standard(proto: "particles_100um"),
|
||||
12: .standard(proto: "particles_100um")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -611,7 +611,7 @@ extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
1: .same(proto: "time"),
|
||||
2: .standard(proto: "device_metrics"),
|
||||
3: .standard(proto: "environment_metrics"),
|
||||
4: .standard(proto: "air_quality_metrics"),
|
||||
4: .standard(proto: "air_quality_metrics")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import SwiftProtobuf
|
|||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
private struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ extension XModem.Control: CaseIterable {
|
|||
.ack,
|
||||
.nak,
|
||||
.can,
|
||||
.ctrlz,
|
||||
.ctrlz
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ extension XModem.Control: @unchecked Sendable {}
|
|||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
fileprivate let _protobuf_package = "meshtastic"
|
||||
private let _protobuf_package = "meshtastic"
|
||||
|
||||
extension XModem: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".XModem"
|
||||
|
|
@ -117,7 +117,7 @@ extension XModem: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas
|
|||
1: .same(proto: "control"),
|
||||
2: .same(proto: "seq"),
|
||||
3: .same(proto: "crc16"),
|
||||
4: .same(proto: "buffer"),
|
||||
4: .same(proto: "buffer")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -170,6 +170,6 @@ extension XModem.Control: SwiftProtobuf._ProtoNameProviding {
|
|||
6: .same(proto: "ACK"),
|
||||
21: .same(proto: "NAK"),
|
||||
24: .same(proto: "CAN"),
|
||||
26: .same(proto: "CTRLZ"),
|
||||
26: .same(proto: "CTRLZ")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@ import ActivityKit
|
|||
#endif
|
||||
|
||||
struct Connect: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
@State var node: NodeInfoEntity? = nil
|
||||
@State var node: NodeInfoEntity?
|
||||
@State var isUnsetRegion = false
|
||||
@State var invalidFirmwareVersion = false
|
||||
@State var liveActivityStarted = false
|
||||
@State var presentingSwitchPreferredPeripheral = false
|
||||
@State var selectedPeripherialId = ""
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
VStack {
|
||||
List {
|
||||
|
|
@ -63,7 +63,7 @@ struct Connect: View {
|
|||
.font(.caption).foregroundColor(Color.gray)
|
||||
.padding([.top, .bottom])
|
||||
.swipeActions {
|
||||
|
||||
|
||||
Button(role: .destructive) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
|
|
@ -72,8 +72,8 @@ struct Connect: View {
|
|||
Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
|
||||
}
|
||||
}
|
||||
.contextMenu{
|
||||
|
||||
.contextMenu {
|
||||
|
||||
if node != nil {
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
if #available(iOS 16.2, *) {
|
||||
|
|
@ -114,7 +114,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
if bleManager.isConnecting {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
|
|
@ -129,7 +129,7 @@ struct Connect: View {
|
|||
.foregroundColor(.orange)
|
||||
} else {
|
||||
VStack {
|
||||
|
||||
|
||||
Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -137,9 +137,9 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if bleManager.lastConnectionError.count > 0 {
|
||||
Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red)
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
.textCase(nil)
|
||||
|
||||
|
||||
if !self.bleManager.isConnected {
|
||||
Section(header: Text("available.radios").font(.title)) {
|
||||
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name > $1.name })) { peripheral in
|
||||
|
|
@ -183,7 +183,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
.confirmationDialog("Connecting to a new radio will clear all local app data on the phone.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) {
|
||||
|
||||
|
||||
Button("Connect to new radio?", role: .destructive) {
|
||||
bleManager.stopScanning()
|
||||
bleManager.connectedPeripheral = nil
|
||||
|
|
@ -191,9 +191,9 @@ struct Connect: View {
|
|||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral()
|
||||
}
|
||||
|
||||
|
||||
clearCoreDataDatabase(context: context)
|
||||
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId} )
|
||||
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId})
|
||||
bleManager.connectTo(peripheral: radio!.peripheral)
|
||||
presentingSwitchPreferredPeripheral = false
|
||||
selectedPeripherialId = ""
|
||||
|
|
@ -201,14 +201,14 @@ struct Connect: View {
|
|||
}
|
||||
.textCase(nil)
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
Text("bluetooth.off")
|
||||
.foregroundColor(.red)
|
||||
.font(.title)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
#if targetEnvironment(macCatalyst)
|
||||
|
|
@ -236,23 +236,23 @@ struct Connect: View {
|
|||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
}
|
||||
.sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) {
|
||||
.sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) {
|
||||
InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion)
|
||||
.presentationDetents([.large])
|
||||
.presentationDragIndicator(.automatic)
|
||||
}
|
||||
.onChange(of: (self.bleManager.invalidVersion)) { cv in
|
||||
.onChange(of: (self.bleManager.invalidVersion)) { _ in
|
||||
invalidFirmwareVersion = self.bleManager.invalidVersion
|
||||
}
|
||||
.onChange(of: (self.bleManager.isSubscribed)) { sub in
|
||||
|
||||
|
||||
if userSettings.preferredPeripheralId.count > 0 && sub {
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(bleManager.connectedPeripheral?.num ?? -1))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, check it for a region
|
||||
if !fetchedNode.isEmpty {
|
||||
|
|
@ -264,14 +264,14 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear(perform: {
|
||||
self.bleManager.context = context
|
||||
self.bleManager.userSettings = userSettings
|
||||
|
||||
|
||||
// Ask for notification permission
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
|
||||
if success {
|
||||
|
|
@ -287,17 +287,17 @@ struct Connect: View {
|
|||
if #available(iOS 16.2, *) {
|
||||
liveActivityStarted = true
|
||||
let timerSeconds = 60
|
||||
|
||||
|
||||
let mostRecent = node?.telemetries?.lastObject as! TelemetryEntity
|
||||
|
||||
|
||||
let activityAttributes = MeshActivityAttributes(nodeNum: Int(node?.num ?? 0), name: node?.user?.longName ?? "unknown")
|
||||
|
||||
|
||||
let future = Date(timeIntervalSinceNow: Double(timerSeconds))
|
||||
|
||||
|
||||
let initialContentState = MeshActivityAttributes.ContentState(timerRange: Date.now...future, connected: true, channelUtilization: mostRecent.channelUtilization, airtime: mostRecent.airUtilTx, batteryLevel: UInt32(mostRecent.batteryLevel))
|
||||
|
||||
|
||||
let activityContent = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .minute, value: 2, to: Date())!)
|
||||
|
||||
|
||||
do {
|
||||
let myActivity = try Activity<MeshActivityAttributes>.request(attributes: activityAttributes, content: activityContent,
|
||||
pushType: nil)
|
||||
|
|
@ -307,7 +307,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func endActivity() {
|
||||
liveActivityStarted = false
|
||||
Task {
|
||||
|
|
@ -322,7 +322,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if os(iOS)
|
||||
func postNotification() {
|
||||
let timerSeconds = 60
|
||||
|
|
@ -344,7 +344,7 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
func didDismissSheet() {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,20 @@
|
|||
import SwiftUI
|
||||
|
||||
struct InvalidVersion: View {
|
||||
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
|
||||
@State var minimumVersion = ""
|
||||
@State var version = ""
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
|
||||
Text("update.firmware")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
Divider()
|
||||
VStack {
|
||||
Text("The Meshtastic Apple apps support firmware version \(minimumVersion) and above.")
|
||||
|
|
@ -36,7 +36,7 @@ struct InvalidVersion: View {
|
|||
.padding()
|
||||
Divider()
|
||||
.padding(.top)
|
||||
VStack{
|
||||
VStack {
|
||||
Text("🦕 End of life Version 🦖 ☄️")
|
||||
.font(.title3)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -46,20 +46,20 @@ struct InvalidVersion: View {
|
|||
.padding([.leading, .trailing, .bottom])
|
||||
Link("Version 1.2 End of life (EOL) Info", destination: URL(string: "https://meshtastic.org/docs/1.2-End-of-life/")!)
|
||||
.font(.callout)
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Button {
|
||||
dismiss()
|
||||
} label: {
|
||||
Label("close", systemImage: "xmark")
|
||||
|
||||
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
#endif
|
||||
|
||||
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
|
||||
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
@State private var selection: Tab = .ble
|
||||
|
||||
|
||||
enum Tab {
|
||||
case contacts
|
||||
case messages
|
||||
|
|
@ -18,11 +18,11 @@ struct ContentView: View {
|
|||
case nodes
|
||||
case settings
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
TabView(selection: $selection) {
|
||||
|
||||
|
||||
Contacts()
|
||||
.tabItem {
|
||||
Label("messages", systemImage: "message")
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ import SwiftUI
|
|||
import Charts
|
||||
|
||||
struct BatteryGauge: View {
|
||||
|
||||
@State var batteryLevel = 0.0
|
||||
|
||||
private let minValue = 1.0
|
||||
private let maxValue = 100.00
|
||||
|
||||
|
|
@ -24,7 +22,6 @@ struct BatteryGauge: View {
|
|||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else {
|
||||
|
||||
let gradient = Gradient(colors: [.red, .orange, .green])
|
||||
Gauge(value: batteryLevel, in: minValue...maxValue) {
|
||||
if batteryLevel > 1.0 && batteryLevel < 10 {
|
||||
|
|
@ -52,7 +49,6 @@ struct BatteryGauge: View {
|
|||
|
||||
struct BatteryGauge_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
VStack {
|
||||
BatteryGauge(batteryLevel: 0.0)
|
||||
BatteryGauge(batteryLevel: 9.0)
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ struct CircleText: View {
|
|||
var brightness: Double? = 0
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
let font = Font.system(size: fontSize!)
|
||||
|
||||
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(color)
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@ import SwiftUI
|
|||
//
|
||||
struct DateTimeText: View {
|
||||
var dateTime: Date?
|
||||
|
||||
|
||||
let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date())
|
||||
|
||||
var body: some View {
|
||||
if (dateTime != nil && dateTime! >= sixMonthsAgo!){
|
||||
|
||||
if dateTime != nil && dateTime! >= sixMonthsAgo! {
|
||||
|
||||
Text("\(dateTime!, style: .date) \(dateTime!, style: .time)")
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
Text("unknown.age")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ import CoreLocation
|
|||
import MapKit
|
||||
|
||||
struct DistanceText: View {
|
||||
|
||||
|
||||
var meters: CLLocationDistance
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
let distanceFormatter = MKDistanceFormatter()
|
||||
Text("distance")+Text(": \(distanceFormatter.string(fromDistance: Double(meters)))")
|
||||
}
|
||||
}
|
||||
struct DistanceText_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
DistanceText(meters: 100)
|
||||
DistanceText(meters: 1000)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ struct LastHeardText: View {
|
|||
var lastHeard: Date?
|
||||
let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date())
|
||||
var body: some View {
|
||||
if (lastHeard != nil && lastHeard! >= sixMonthsAgo!){
|
||||
if lastHeard != nil && lastHeard! >= sixMonthsAgo! {
|
||||
Text("heard")+Text(": \(lastHeard!, style: .relative) ")+Text("ago")
|
||||
} else {
|
||||
Text("unknown.age")
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MeshtasticLogo: View {
|
||||
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
VStack {
|
||||
Image("logo-white")
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessageTemplate: View {
|
||||
|
||||
|
||||
var user: UserEntity
|
||||
var message: MessageEntity
|
||||
var messageReply: MessageEntity?
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
// Display the message being replied to and the arrow
|
||||
if message.replyID > 0 {
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.blue).font(.caption2)
|
||||
|
|
@ -31,8 +31,8 @@ struct MessageTemplate: View {
|
|||
.padding(.trailing)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Message
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import SwiftUI
|
|||
|
||||
struct NodeAnnotation: View {
|
||||
let time: Date
|
||||
|
||||
|
||||
let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date())
|
||||
|
||||
var body: some View {
|
||||
|
||||
if (time >= sixMonthsAgo!) {
|
||||
|
||||
|
||||
if time >= sixMonthsAgo! {
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Text(time, style: .offset)
|
||||
.font(.caption2).foregroundColor(.accentColor)
|
||||
|
|
@ -17,9 +17,9 @@ struct NodeAnnotation: View {
|
|||
.background(Color(.white))
|
||||
.cornerRadius(10)
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Text("unknown.age")
|
||||
.font(.caption2).foregroundColor(.accentColor)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import SwiftUI
|
|||
|
||||
struct SignalStrengthIndicator: View {
|
||||
let signalStrength: SignalStrength
|
||||
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ForEach(0..<3) { bar in
|
||||
|
|
@ -44,7 +44,7 @@ struct SignalStrengthIndicator: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func getColor() -> Color {
|
||||
switch signalStrength {
|
||||
case .weak:
|
||||
|
|
@ -71,7 +71,7 @@ extension Shape {
|
|||
}
|
||||
}
|
||||
|
||||
enum SignalStrength : Int {
|
||||
enum SignalStrength: Int {
|
||||
case weak = 0
|
||||
case normal = 1
|
||||
case strong = 2
|
||||
|
|
|
|||
|
|
@ -10,14 +10,13 @@ struct AirQualityIndexCompact: View {
|
|||
var aqi: Int
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
HStack (spacing: 0.5) {
|
||||
HStack(spacing: 0.5) {
|
||||
Text("AQI \(aqi)")
|
||||
.foregroundColor(.gray)
|
||||
.padding(.trailing, 0)
|
||||
.font(.caption)
|
||||
|
||||
|
||||
if aqi > 0 && aqi < 51 {
|
||||
// Good
|
||||
Circle()
|
||||
|
|
@ -38,7 +37,7 @@ struct AirQualityIndexCompact: View {
|
|||
Circle()
|
||||
.fill(.orange)
|
||||
.frame(width: 10, height: 10)
|
||||
|
||||
|
||||
} else if aqi > 300 && aqi < 401 {
|
||||
// Very Poor
|
||||
Circle()
|
||||
|
|
@ -55,7 +54,7 @@ struct AirQualityIndexCompact: View {
|
|||
}
|
||||
struct AQICircleDisplay_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
AirQualityIndexCompact(aqi: 5)
|
||||
AirQualityIndexCompact(aqi: 51)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct CurrentConditionsCompact: View {
|
|||
}
|
||||
struct CurrentConditionsCompact_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
CurrentConditionsCompact(temp: 22, condition: WeatherConditions.clear)
|
||||
CurrentConditionsCompact(temp: 17, condition: WeatherConditions.cloudy)
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ import WeatherKit
|
|||
|
||||
struct NodeWeatherForecastView: View {
|
||||
var location: CLLocation
|
||||
|
||||
|
||||
@State private var forecast: NodeWeatherForecast = placeholderForecast
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
chart
|
||||
.frame(width: 400)
|
||||
}
|
||||
//.frame(width: 350, height: 200)
|
||||
// .frame(width: 350, height: 200)
|
||||
.padding(10)
|
||||
.background()
|
||||
.task {
|
||||
|
|
@ -38,12 +38,12 @@ struct NodeWeatherForecastView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var chart: some View {
|
||||
Chart {
|
||||
areaMarks(seriesKey: "Temperature", value: 0)
|
||||
.foregroundStyle(.linearGradient(colors: [.teal, .yellow], startPoint: .bottom, endPoint: .top))
|
||||
|
||||
|
||||
ForEach(forecast.nightTimeRanges, id: \.lowerBound) { range in
|
||||
RectangleMark(
|
||||
xStart: .value("Hour", range.lowerBound),
|
||||
|
|
@ -53,7 +53,7 @@ struct NodeWeatherForecastView: View {
|
|||
.mask {
|
||||
areaMarks(seriesKey: "Mask", value: range.lowerBound.timeIntervalSince1970)
|
||||
}
|
||||
|
||||
|
||||
if range.lowerBound != forecast.entries.first!.date {
|
||||
let date = range.lowerBound
|
||||
RectangleMark(
|
||||
|
|
@ -71,7 +71,7 @@ struct NodeWeatherForecastView: View {
|
|||
.foregroundStyle(.white, .indigo)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if range.upperBound != forecast.entries.last!.date {
|
||||
let date = range.upperBound
|
||||
RectangleMark(
|
||||
|
|
@ -107,7 +107,7 @@ struct NodeWeatherForecastView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ChartContentBuilder
|
||||
func areaMarks(seriesKey: String, value: Double) -> some ChartContent {
|
||||
ForEach(forecast.entries) { entry in
|
||||
|
|
@ -120,14 +120,14 @@ struct NodeWeatherForecastView: View {
|
|||
.interpolationMethod(.catmullRom)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static var placeholderForecast: NodeWeatherForecast {
|
||||
func entry(hourOffset: Int, degrees: Double, isDaylight: Bool) -> NodeWeatherForecast.WeatherEntry {
|
||||
let startDate = Calendar.current.date(from: DateComponents(year: 2022, month: 5, day: 6, hour: 9))!
|
||||
let date = Calendar.current.date(byAdding: DateComponents(hour: hourOffset), to: startDate)!
|
||||
return NodeWeatherForecast.WeatherEntry(date: date, degrees: degrees, isDaylight: isDaylight)
|
||||
}
|
||||
|
||||
|
||||
return NodeWeatherForecast(entries: [
|
||||
entry(hourOffset: 0, degrees: 63, isDaylight: true),
|
||||
entry(hourOffset: 1, degrees: 68, isDaylight: true),
|
||||
|
|
@ -165,17 +165,17 @@ struct NodeWeatherForecast {
|
|||
var degrees: Double
|
||||
var isDaylight: Bool
|
||||
}
|
||||
|
||||
|
||||
var entries: [WeatherEntry]
|
||||
|
||||
|
||||
var low: Double {
|
||||
return entries.map(\.degrees).min()! - 2
|
||||
}
|
||||
|
||||
|
||||
var hottestEntry: WeatherEntry {
|
||||
return entries.sorted { $0.degrees > $1.degrees }.first!
|
||||
}
|
||||
|
||||
|
||||
var nightTimeRanges: [Range<Date>] {
|
||||
var currentLowerBound: Date?
|
||||
var results: [Range<Date>] = []
|
||||
|
|
@ -192,7 +192,7 @@ struct NodeWeatherForecast {
|
|||
}
|
||||
return results
|
||||
}
|
||||
|
||||
|
||||
var binRange: ClosedRange<Date> {
|
||||
let startDate: Date = entries.map(\.date).first(where: {
|
||||
Calendar.current.component(.hour, from: $0).isMultiple(of: 3)
|
||||
|
|
@ -202,7 +202,7 @@ struct NodeWeatherForecast {
|
|||
})!
|
||||
return startDate ... endDate
|
||||
}
|
||||
|
||||
|
||||
func temperature(at date: Date) -> Double {
|
||||
entries.first(where: { $0.date == date })!.degrees
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ extension MKMapRect {
|
|||
left = min(left, coordinate.longitude)
|
||||
right = max(right, coordinate.longitude)
|
||||
}
|
||||
let topLeft = MKMapPoint(CLLocationCoordinate2D(latitude:top, longitude:left))
|
||||
let bottomRight = MKMapPoint(CLLocationCoordinate2D(latitude:bottom, longitude:right))
|
||||
self = MKMapRect(x:topLeft.x, y:topLeft.y,
|
||||
width:bottomRight.x - topLeft.x, height:bottomRight.y - topLeft.y)
|
||||
let topLeft = MKMapPoint(CLLocationCoordinate2D(latitude: top, longitude: left))
|
||||
let bottomRight = MKMapPoint(CLLocationCoordinate2D(latitude: bottom, longitude: right))
|
||||
self = MKMapRect(x: topLeft.x, y: topLeft.y,
|
||||
width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,32 +48,32 @@ class LocalMBTileOverlay: MKTileOverlay {
|
|||
return _boundingMapRect
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init?(mbTilePath path: String) {
|
||||
|
||||
|
||||
super.init(urlTemplate: nil)
|
||||
self.path = path
|
||||
do {
|
||||
self.mb = try Connection(self.path, readonly: true)
|
||||
let metadata = Table("metadata")
|
||||
|
||||
|
||||
let name = Expression<String>("name")
|
||||
let value = Expression<String>("value")
|
||||
|
||||
//make sure it's raster
|
||||
|
||||
// make sure it's raster
|
||||
let formatQuery = try mb.pluck(metadata.select(value).filter(name == "format"))
|
||||
if formatQuery?[value] == nil || (formatQuery![value] != "jpg" && formatQuery![value] != "png") {
|
||||
throw MapTileError.invalidFormat
|
||||
}
|
||||
|
||||
|
||||
let minZQuery = try mb.pluck(metadata.select(value).filter(name == "minzoom"))
|
||||
self.minimumZ = Int(minZQuery![value])!
|
||||
|
||||
|
||||
let maxZQuery = try mb.pluck(metadata.select(value).filter(name == "maxzoom"))
|
||||
self.maximumZ = Int(maxZQuery![value])!
|
||||
|
||||
|
||||
self.isGeometryFlipped = true
|
||||
|
||||
|
||||
let boundingBoxString = try mb.pluck(metadata.select(value).filter(name == "bounds"))
|
||||
let boundCoords = boundingBoxString![value].split(separator: ",")
|
||||
let coords = [
|
||||
|
|
@ -83,15 +83,15 @@ class LocalMBTileOverlay: MKTileOverlay {
|
|||
longitude: Double(boundCoords[2]) ?? 0)
|
||||
]
|
||||
self._boundingMapRect = MKMapRect(coordinates: coords)
|
||||
|
||||
|
||||
} catch {
|
||||
print("💥 Map tile error: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func loadTile(at path: MKTileOverlayPath, result: @escaping (Data?, Error?) -> Void) {
|
||||
|
||||
|
||||
let tileX = Int64(path.x)
|
||||
let tileY = Int64(path.y)
|
||||
let tileZ = Int64(path.z)
|
||||
|
|
@ -99,9 +99,9 @@ class LocalMBTileOverlay: MKTileOverlay {
|
|||
let zoomLevel = Expression<Int64>("zoom_level")
|
||||
let tileColumn = Expression<Int64>("tile_column")
|
||||
let tileRow = Expression<Int64>("tile_row")
|
||||
|
||||
|
||||
if let dataQuery = try? self.mb.pluck(Table("tiles").select(tileData).filter(zoomLevel == tileZ).filter(tileColumn == tileX).filter(tileRow == tileY)) {
|
||||
let data = Data(bytes: dataQuery[tileData].bytes, count: dataQuery[tileData].bytes.count)//dataQuery![tileData].bytes
|
||||
let data = Data(bytes: dataQuery[tileData].bytes, count: dataQuery[tileData].bytes.count)// dataQuery![tileData].bytes
|
||||
result(data, nil)
|
||||
} else {
|
||||
print("💥 No tile here: x:\(tileX) y:\(tileY) z:\(tileZ)")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import MapKit
|
||||
|
||||
extension MKMapView {
|
||||
|
||||
|
||||
func fitAllAnnotations(with padding: UIEdgeInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)) {
|
||||
var zoomRect: MKMapRect = .null
|
||||
annotations.forEach({
|
||||
|
|
@ -16,10 +16,10 @@ extension MKMapView {
|
|||
let pointRect = MKMapRect(x: annotationPoint.x, y: annotationPoint.y, width: 0.01, height: 0.01)
|
||||
zoomRect = zoomRect.union(pointRect)
|
||||
})
|
||||
|
||||
|
||||
setVisibleMapRect(zoomRect, edgePadding: padding, animated: true)
|
||||
}
|
||||
|
||||
|
||||
func fit(annotations: [MKAnnotation], andShow show: Bool, with padding: UIEdgeInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)) {
|
||||
var zoomRect: MKMapRect = .null
|
||||
annotations.forEach({
|
||||
|
|
@ -27,11 +27,11 @@ extension MKMapView {
|
|||
let rect = MKMapRect(x: aPoint.x, y: aPoint.y, width: 0.1, height: 0.1)
|
||||
zoomRect = zoomRect.isNull ? rect : zoomRect.union(rect)
|
||||
})
|
||||
|
||||
|
||||
if show {
|
||||
addAnnotations(annotations)
|
||||
}
|
||||
|
||||
|
||||
setVisibleMapRect(zoomRect, edgePadding: padding, animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
////
|
||||
//// Created by Cem Yilmaz on 05.07.21.
|
||||
////
|
||||
//import SwiftUI
|
||||
//import MapKit
|
||||
//import CoreData
|
||||
// import SwiftUI
|
||||
// import MapKit
|
||||
// import CoreData
|
||||
//
|
||||
//#if canImport(MapKit) && canImport(UIKit)
|
||||
//public struct MapView: UIViewRepresentable {
|
||||
// #if canImport(MapKit) && canImport(UIKit)
|
||||
// public struct MapView: UIViewRepresentable {
|
||||
//
|
||||
// @Environment(\.managedObjectContext) var context
|
||||
//
|
||||
|
|
@ -463,7 +463,7 @@
|
|||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
// }
|
||||
//
|
||||
//// MARK: End of implementation
|
||||
//#endif
|
||||
// MARK: End of implementation
|
||||
// #endif
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ func degreesToRadians(_ number: Double) -> Double {
|
|||
}
|
||||
|
||||
struct MapViewSwiftUI: UIViewRepresentable {
|
||||
|
||||
|
||||
var onLongPress: (_ waypointCoordinate: CLLocationCoordinate2D) -> Void
|
||||
var onWaypointEdit: (_ waypointId: Int ) -> Void
|
||||
let mapView = MKMapView()
|
||||
|
|
@ -21,19 +21,19 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
let mapViewType: MKMapType
|
||||
let userTrackingMode: MKUserTrackingMode
|
||||
let centeringMode: CenteringMode
|
||||
|
||||
|
||||
let centerOnPositionsOnly: Bool
|
||||
@AppStorage("meshMapRecentering") private var recenter: Bool = false
|
||||
|
||||
|
||||
// Offline Maps
|
||||
//make this view dependent on the UserDefault that is updated when importing a new map file
|
||||
// make this view dependent on the UserDefault that is updated when importing a new map file
|
||||
@AppStorage("lastUpdatedLocalMapFile") private var lastUpdatedLocalMapFile = 0
|
||||
@State private var loadedLastUpdatedLocalMapFile = 0
|
||||
var customMapOverlay: CustomMapOverlay?
|
||||
@State private var presentCustomMapOverlayHash: CustomMapOverlay?
|
||||
var overlays: [Overlay] = []
|
||||
let dynamicRegion: Bool = true
|
||||
|
||||
|
||||
func makeUIView(context: Context) -> MKMapView {
|
||||
// Map View Parameters
|
||||
mapView.mapType = mapViewType
|
||||
|
|
@ -63,7 +63,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
mapView.addAnnotations(positions)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Other MKMapView Settings
|
||||
mapView.preferredConfiguration.elevationStyle = .realistic// .flat
|
||||
mapView.isPitchEnabled = true
|
||||
|
|
@ -73,14 +73,14 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
mapView.showsBuildings = true
|
||||
mapView.showsScale = true
|
||||
mapView.showsTraffic = true
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
// Show the default always visible compass and the mac only controls
|
||||
mapView.showsCompass = true
|
||||
mapView.showsZoomControls = true
|
||||
mapView.showsPitchControl = true
|
||||
#else
|
||||
|
||||
|
||||
#if os(iOS)
|
||||
// Hide the default compass that only appears when you are not going north and instead always show the compass in the bottom right corner of the map
|
||||
mapView.showsCompass = false
|
||||
|
|
@ -91,26 +91,26 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
compassButton.trailingAnchor.constraint(equalTo: mapView.trailingAnchor, constant: -5).isActive = true
|
||||
compassButton.bottomAnchor.constraint(equalTo: mapView.bottomAnchor, constant: -25).isActive = true
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
mapView.delegate = context.coordinator
|
||||
return mapView
|
||||
}
|
||||
|
||||
|
||||
func updateUIView(_ mapView: MKMapView, context: Context) {
|
||||
mapView.mapType = mapViewType
|
||||
|
||||
|
||||
if self.customMapOverlay != self.presentCustomMapOverlayHash || self.loadedLastUpdatedLocalMapFile != self.lastUpdatedLocalMapFile {
|
||||
mapView.removeOverlays(mapView.overlays)
|
||||
if self.customMapOverlay != nil {
|
||||
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
let tilePath = documentsDirectory.appendingPathComponent("offline_map.mbtiles", isDirectory: false).path
|
||||
if fileManager.fileExists(atPath: tilePath) {
|
||||
print("Loading local map file")
|
||||
if let overlay = LocalMBTileOverlay(mbTilePath: tilePath) {
|
||||
overlay.canReplaceMapContent = false//customMapOverlay.canReplaceMapContent
|
||||
overlay.canReplaceMapContent = false// customMapOverlay.canReplaceMapContent
|
||||
mapView.addOverlay(overlay)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -122,9 +122,9 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
self.loadedLastUpdatedLocalMapFile = self.lastUpdatedLocalMapFile
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
|
||||
let annotationCount = waypoints.count + positions.count
|
||||
if annotationCount != mapView.annotations.count {
|
||||
mapView.removeAnnotations(mapView.annotations)
|
||||
|
|
@ -151,17 +151,17 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func makeCoordinator() -> MapCoordinator {
|
||||
return Coordinator(self)
|
||||
}
|
||||
|
||||
|
||||
final class MapCoordinator: NSObject, MKMapViewDelegate, UIGestureRecognizerDelegate {
|
||||
|
||||
|
||||
var parent: MapViewSwiftUI
|
||||
var longPressRecognizer = UILongPressGestureRecognizer()
|
||||
var overlays: [Overlay] = []
|
||||
|
||||
|
||||
init(_ parent: MapViewSwiftUI) {
|
||||
self.parent = parent
|
||||
super.init()
|
||||
|
|
@ -172,22 +172,21 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
self.parent.mapView.addGestureRecognizer(longPressRecognizer)
|
||||
self.overlays = []
|
||||
}
|
||||
|
||||
|
||||
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
||||
|
||||
|
||||
switch annotation {
|
||||
case let positionAnnotation as PositionEntity:
|
||||
let reuseID = String(positionAnnotation.nodePosition?.num ?? 0) + "-" + String(positionAnnotation.time?.timeIntervalSince1970 ?? 0)
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "node") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: reuseID )
|
||||
annotationView.tag = -1
|
||||
annotationView.canShowCallout = true
|
||||
|
||||
|
||||
if positionAnnotation.latest {
|
||||
annotationView.markerTintColor = .systemRed
|
||||
annotationView.displayPriority = .required
|
||||
annotationView.titleVisibility = .visible
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
annotationView.markerTintColor = UIColor(.indigo)
|
||||
annotationView.displayPriority = .defaultHigh
|
||||
annotationView.titleVisibility = .adaptive
|
||||
|
|
@ -205,10 +204,10 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
let distanceFormatter = MKDistanceFormatter()
|
||||
subtitle.text! += "Altitude: \(distanceFormatter.string(fromDistance: Double(positionAnnotation.altitude))) \n"
|
||||
if positionAnnotation.nodePosition?.metadata != nil {
|
||||
|
||||
|
||||
if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.client ||
|
||||
DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.clientMute ||
|
||||
DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.routerClient{
|
||||
DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.routerClient {
|
||||
annotationView.glyphImage = UIImage(systemName: "flipphone")
|
||||
} else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.repeater {
|
||||
annotationView.glyphImage = UIImage(systemName: "repeat")
|
||||
|
|
@ -219,7 +218,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
} else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.sensor {
|
||||
annotationView.glyphImage = UIImage(systemName: "sensor")
|
||||
}
|
||||
|
||||
|
||||
let pf = PositionFlags(rawValue: Int(positionAnnotation.nodePosition?.metadata?.positionFlags ?? 3))
|
||||
if pf.contains(.Satsinview) {
|
||||
subtitle.text! += "Sats in view: \(String(positionAnnotation.satsInView)) \n"
|
||||
|
|
@ -227,8 +226,8 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
if pf.contains(.SeqNo) {
|
||||
subtitle.text! += "Sequence: \(String(positionAnnotation.seqNo)) \n"
|
||||
}
|
||||
if pf.contains(.Heading){
|
||||
|
||||
if pf.contains(.Heading) {
|
||||
|
||||
if parent.userTrackingMode != MKUserTrackingMode.followWithHeading {
|
||||
annotationView.glyphImage = UIImage(systemName: "location.north.fill")?.rotate(radians: Float(degreesToRadians(Double(positionAnnotation.heading))))
|
||||
subtitle.text! += "Heading: \(String(positionAnnotation.heading)) \n"
|
||||
|
|
@ -244,7 +243,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
}
|
||||
subtitle.text! += "Speed: \(formatter.string(from: Measurement(value: Double(positionAnnotation.speed), unit: UnitSpeed.kilometersPerHour))) \n"
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// node metadata is nil
|
||||
annotationView.glyphImage = UIImage(systemName: "flipphone")
|
||||
|
|
@ -279,8 +278,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
let subtitle = UILabel()
|
||||
if waypointAnnotation.longDescription?.count ?? 0 > 0 {
|
||||
subtitle.text = (waypointAnnotation.longDescription ?? "") + "\n"
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
subtitle.text = ""
|
||||
}
|
||||
if LocationHelper.currentLocation.distance(from: LocationHelper.DefaultLocation) > 0.0 {
|
||||
|
|
@ -306,23 +304,23 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
|
||||
// Only Allow Edit for waypoint annotations with a id
|
||||
if view.tag > 0 {
|
||||
parent.onWaypointEdit(view.tag)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func longPressHandler(_ gesture: UILongPressGestureRecognizer) {
|
||||
|
||||
|
||||
if gesture.state != UIGestureRecognizer.State.ended {
|
||||
return
|
||||
} else if gesture.state != UIGestureRecognizer.State.began {
|
||||
|
||||
|
||||
// Screen Position - CGPoint
|
||||
let location = longPressRecognizer.location(in: self.parent.mapView)
|
||||
|
||||
|
||||
// Map Coordinate - CLLocationCoordinate2D
|
||||
let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView)
|
||||
let annotation = MKPointAnnotation()
|
||||
|
|
@ -333,11 +331,11 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
parent.onLongPress(coordinate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
|
||||
|
||||
|
||||
if let index = self.overlays.firstIndex(where: { overlay_ in overlay_.shape.hash == overlay.hash }) {
|
||||
|
||||
|
||||
let unwrappedOverlay = self.overlays[index]
|
||||
if let circleOverlay = unwrappedOverlay.shape as? MKCircle {
|
||||
let renderer = MKCircleRenderer(circle: circleOverlay)
|
||||
|
|
@ -379,18 +377,18 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// is supposed to be located in the folder with the map name
|
||||
public struct DefaultTile: Hashable {
|
||||
let tileName: String
|
||||
let tileType: String
|
||||
|
||||
|
||||
public init(tileName: String, tileType: String) {
|
||||
self.tileName = tileName
|
||||
self.tileType = tileType
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct CustomMapOverlay: Equatable, Hashable {
|
||||
let mapName: String
|
||||
let tileType: String
|
||||
|
|
@ -398,7 +396,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
var minimumZoomLevel: Int?
|
||||
var maximumZoomLevel: Int?
|
||||
let defaultTile: DefaultTile?
|
||||
|
||||
|
||||
public init(
|
||||
mapName: String,
|
||||
tileType: String,
|
||||
|
|
@ -414,7 +412,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
self.maximumZoomLevel = maximumZoomLevel
|
||||
self.defaultTile = defaultTile
|
||||
}
|
||||
|
||||
|
||||
public init?(
|
||||
mapName: String?,
|
||||
tileType: String,
|
||||
|
|
@ -423,7 +421,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
maximumZoomLevel: Int? = nil,
|
||||
defaultTile: DefaultTile? = nil
|
||||
) {
|
||||
if (mapName == nil || mapName! == "") {
|
||||
if mapName == nil || mapName! == "" {
|
||||
return nil
|
||||
}
|
||||
self.mapName = mapName!
|
||||
|
|
@ -434,15 +432,15 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
self.defaultTile = defaultTile
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class CustomMapOverlaySource: MKTileOverlay {
|
||||
|
||||
|
||||
// requires folder: tiles/{mapName}/z/y/y,{tileType}
|
||||
private var parent: MapViewSwiftUI
|
||||
private let mapName: String
|
||||
private let tileType: String
|
||||
private let defaultTile: DefaultTile?
|
||||
|
||||
|
||||
public init(
|
||||
parent: MapViewSwiftUI,
|
||||
mapName: String,
|
||||
|
|
@ -455,7 +453,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
self.defaultTile = defaultTile
|
||||
super.init(urlTemplate: "")
|
||||
}
|
||||
|
||||
|
||||
public override func url(forTilePath path: MKTileOverlayPath) -> URL {
|
||||
if let tileUrl = Bundle.main.url(
|
||||
forResource: "\(path.y)",
|
||||
|
|
@ -477,21 +475,21 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Overlay {
|
||||
|
||||
|
||||
public static func == (lhs: MapViewSwiftUI.Overlay, rhs: MapViewSwiftUI.Overlay) -> Bool {
|
||||
// maybe to use in the future for comparison of full array
|
||||
lhs.shape.coordinate.latitude == rhs.shape.coordinate.latitude &&
|
||||
lhs.shape.coordinate.longitude == rhs.shape.coordinate.longitude &&
|
||||
lhs.fillColor == rhs.fillColor
|
||||
}
|
||||
|
||||
|
||||
var shape: MKOverlay
|
||||
var fillColor: UIColor?
|
||||
var strokeColor: UIColor?
|
||||
var lineWidth: CGFloat
|
||||
|
||||
|
||||
public init(
|
||||
shape: MKOverlay,
|
||||
fillColor: UIColor? = nil,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
//// Created by Joshua Pirihi on 24/12/21.
|
||||
////
|
||||
//
|
||||
//import UIKit
|
||||
//import MapKit
|
||||
//import SwiftUI
|
||||
// import UIKit
|
||||
// import MapKit
|
||||
// import SwiftUI
|
||||
//
|
||||
//// a simple circle annotation, with a string in it
|
||||
//class PositionAnnotation: NSObject, MKAnnotation {
|
||||
// class PositionAnnotation: NSObject, MKAnnotation {
|
||||
//
|
||||
// // This property must be key-value observable, which the `@objc dynamic` attributes provide.
|
||||
// @objc dynamic var coordinate = CLLocationCoordinate2D(latitude: 0, longitude: 0)
|
||||
|
|
@ -22,9 +22,9 @@
|
|||
// // the text to appear inside the little circle
|
||||
// var shortName: String?
|
||||
//
|
||||
//}
|
||||
// }
|
||||
//
|
||||
//class PositionAnnotationView: MKAnnotationView {
|
||||
// class PositionAnnotationView: MKAnnotationView {
|
||||
//
|
||||
// private let annotationFrame = CGRect(x: 0, y: 0, width: 40, height: 40)
|
||||
// private let label: UILabel
|
||||
|
|
@ -57,4 +57,4 @@
|
|||
// context.setFillColor(Color.accentColor.cgColor ?? CGColor(red: 0, green: 0.5, blue: 1.0, alpha: 1.0))
|
||||
// context.fillEllipse(in: circleRect)
|
||||
// }
|
||||
//}
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ import SwiftUI
|
|||
import CoreLocation
|
||||
|
||||
struct WaypointFormView: View {
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State var coordinate: CLLocationCoordinate2D
|
||||
@State var waypointId : Int = 0
|
||||
|
||||
@State var waypointId: Int = 0
|
||||
|
||||
@FocusState private var iconIsFocused: Bool
|
||||
|
||||
|
||||
@State private var name: String = ""
|
||||
@State private var description: String = ""
|
||||
@State private var icon: String = "📍"
|
||||
|
|
@ -26,9 +26,9 @@ struct WaypointFormView: View {
|
|||
@State private var expire: Date = Date() // = Date.now.addingTimeInterval(60 * 120) // 1 minute * 120 = 2 Hours
|
||||
@State private var locked: Bool = false
|
||||
@State private var lockedTo: Int64 = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
Form {
|
||||
let distance = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude).distance(from: CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude))
|
||||
Section(header: Text((waypointId > 0) ? "Editing Waypoint" : "Create Waypoint")) {
|
||||
|
|
@ -52,7 +52,7 @@ struct WaypointFormView: View {
|
|||
axis: .vertical
|
||||
)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: name, perform: { value in
|
||||
.onChange(of: name, perform: { _ in
|
||||
let totalBytes = name.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 30 {
|
||||
|
|
@ -73,7 +73,7 @@ struct WaypointFormView: View {
|
|||
axis: .vertical
|
||||
)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: description, perform: { value in
|
||||
.onChange(of: description, perform: { _ in
|
||||
let totalBytes = description.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 100 {
|
||||
|
|
@ -92,14 +92,14 @@ struct WaypointFormView: View {
|
|||
.font(.title)
|
||||
.focused($iconIsFocused)
|
||||
.onChange(of: icon) { value in
|
||||
|
||||
|
||||
// If you have anything other than emojis in your string make it empty
|
||||
if !value.onlyEmojis() {
|
||||
icon = ""
|
||||
}
|
||||
// If a second emoji is entered delete the first one
|
||||
if value.count >= 1 {
|
||||
|
||||
|
||||
if value.count > 1 {
|
||||
let index = value.index(value.startIndex, offsetBy: 1)
|
||||
icon = String(value[index])
|
||||
|
|
@ -107,7 +107,7 @@ struct WaypointFormView: View {
|
|||
iconIsFocused = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Toggle(isOn: $expires) {
|
||||
Label("Expires", systemImage: "clock.badge.xmark")
|
||||
|
|
@ -126,9 +126,9 @@ struct WaypointFormView: View {
|
|||
}
|
||||
HStack {
|
||||
Button {
|
||||
|
||||
|
||||
var newWaypoint = Waypoint()
|
||||
|
||||
|
||||
if waypointId > 0 {
|
||||
newWaypoint.id = UInt32(waypointId)
|
||||
} else {
|
||||
|
|
@ -144,7 +144,7 @@ struct WaypointFormView: View {
|
|||
let unicode = unicodeScalers[unicodeScalers.startIndex].value
|
||||
newWaypoint.icon = unicode
|
||||
if locked {
|
||||
|
||||
|
||||
if lockedTo == 0 {
|
||||
newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num)
|
||||
} else {
|
||||
|
|
@ -172,8 +172,8 @@ struct WaypointFormView: View {
|
|||
.controlSize(.large)
|
||||
.disabled(bleManager.connectedPeripheral == nil)
|
||||
.padding(.bottom)
|
||||
|
||||
Button(role:.cancel) {
|
||||
|
||||
Button(role: .cancel) {
|
||||
dismiss()
|
||||
} label: {
|
||||
Label("cancel", systemImage: "x.circle")
|
||||
|
|
@ -184,7 +184,7 @@ struct WaypointFormView: View {
|
|||
.padding(.bottom)
|
||||
|
||||
if waypointId > 0 {
|
||||
|
||||
|
||||
Menu {
|
||||
Button("For me", action: {
|
||||
let waypoint = getWaypoint(id: Int64(waypointId), context: bleManager.context!)
|
||||
|
|
@ -197,10 +197,10 @@ struct WaypointFormView: View {
|
|||
dismiss() })
|
||||
Button("For everyone", action: {
|
||||
var newWaypoint = Waypoint()
|
||||
|
||||
|
||||
if waypointId > 0 {
|
||||
newWaypoint.id = UInt32(waypointId)
|
||||
}
|
||||
}
|
||||
newWaypoint.name = name.count > 0 ? name : "Dropped Pin"
|
||||
newWaypoint.description_p = description
|
||||
newWaypoint.latitudeI = Int32(coordinate.latitude * 1e7)
|
||||
|
|
@ -211,7 +211,7 @@ struct WaypointFormView: View {
|
|||
let unicode = unicodeScalers[unicodeScalers.startIndex].value
|
||||
newWaypoint.icon = unicode
|
||||
if locked {
|
||||
|
||||
|
||||
if lockedTo == 0 {
|
||||
newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num)
|
||||
} else {
|
||||
|
|
@ -241,7 +241,7 @@ struct WaypointFormView: View {
|
|||
}
|
||||
.onChange(of: waypointId) { newId in
|
||||
print(newId)
|
||||
|
||||
|
||||
}
|
||||
.onAppear {
|
||||
if waypointId > 0 {
|
||||
|
|
|
|||
|
|
@ -9,27 +9,27 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct ChannelMessageList: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
enum Field: Hashable {
|
||||
case messageText
|
||||
}
|
||||
|
||||
|
||||
// Keyboard State
|
||||
@State var typingMessage: String = ""
|
||||
@State private var totalBytes = 0
|
||||
var maxbytes = 228
|
||||
@FocusState var focusedField: Field?
|
||||
|
||||
|
||||
@ObservedObject var channel: ChannelEntity
|
||||
@State var showDeleteMessageAlert = false
|
||||
@State private var deleteMessageId: Int64 = 0
|
||||
@State private var replyMessageId: Int64 = 0
|
||||
@State private var sendPositionWithMessage: Bool = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmssa", options: 0, locale: Locale.current)
|
||||
|
|
@ -54,8 +54,8 @@ struct ChannelMessageList: View {
|
|||
.padding(.trailing)
|
||||
}
|
||||
}
|
||||
HStack (alignment: .top) {
|
||||
if currentUser { Spacer(minLength:50) }
|
||||
HStack(alignment: .top) {
|
||||
if currentUser { Spacer(minLength: 50) }
|
||||
if !currentUser {
|
||||
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.gray), circleSize: 44, fontSize: 14)
|
||||
.padding(.all, 5)
|
||||
|
|
@ -71,7 +71,7 @@ struct ChannelMessageList: View {
|
|||
.background(currentUser ? .accentColor : Color(.gray))
|
||||
.cornerRadius(15)
|
||||
.contextMenu {
|
||||
VStack{
|
||||
VStack {
|
||||
Text("channel")+Text(": \(message.channel)")
|
||||
}
|
||||
Menu("tapback") {
|
||||
|
|
@ -81,7 +81,7 @@ struct ChannelMessageList: View {
|
|||
print("Sent \(tb.emojiString) Tapback")
|
||||
self.context.refresh(channel, mergeChanges: true)
|
||||
} else { print("\(tb.emojiString) Tapback Failed") }
|
||||
|
||||
|
||||
}) {
|
||||
Text(tb.description)
|
||||
let image = tb.emojiString.image()
|
||||
|
|
@ -152,11 +152,11 @@ struct ChannelMessageList: View {
|
|||
Image(systemName: "trash")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let tapbacks = message.value(forKey: "tapbacks") as! [MessageEntity]
|
||||
if tapbacks.count > 0 {
|
||||
VStack (alignment: .trailing) {
|
||||
HStack {
|
||||
VStack(alignment: .trailing) {
|
||||
HStack {
|
||||
ForEach( tapbacks ) { (tapback: MessageEntity) in
|
||||
VStack {
|
||||
let image = tapback.messagePayload!.image(fontSize: 20)
|
||||
|
|
@ -193,7 +193,7 @@ struct ChannelMessageList: View {
|
|||
.padding(.bottom)
|
||||
.id(channel.allPrivateMessages.firstIndex(of: message))
|
||||
if !currentUser {
|
||||
Spacer(minLength:50)
|
||||
Spacer(minLength: 50)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
|
|
@ -225,7 +225,7 @@ struct ChannelMessageList: View {
|
|||
scrollView.scrollTo(channel.allPrivateMessages.last!.messageId)
|
||||
}
|
||||
})
|
||||
.onChange(of: channel.allPrivateMessages, perform: { messages in
|
||||
.onChange(of: channel.allPrivateMessages, perform: { _ in
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
scrollView.scrollTo(channel.allPrivateMessages.last!.messageId)
|
||||
}
|
||||
|
|
@ -238,14 +238,14 @@ struct ChannelMessageList: View {
|
|||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
if userSettings.meshtasticUsername.count > 0 {
|
||||
|
||||
|
||||
typingMessage = "📍 " + userSettings.meshtasticUsername + " has shared their position with you from node " + userLongName
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
typingMessage = "📍 " + userLongName + " has shared their position with you."
|
||||
}
|
||||
|
||||
|
||||
} label: {
|
||||
Text("share.position")
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
|
|
@ -261,7 +261,7 @@ struct ChannelMessageList: View {
|
|||
}
|
||||
#endif
|
||||
HStack(alignment: .top) {
|
||||
|
||||
|
||||
ZStack {
|
||||
let kbType = UIKeyboardType(rawValue: UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0)
|
||||
TextField("message", text: $typingMessage, axis: .vertical)
|
||||
|
|
@ -290,20 +290,20 @@ struct ChannelMessageList: View {
|
|||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
if userSettings.meshtasticUsername.count > 0 {
|
||||
|
||||
|
||||
typingMessage = "📍 " + userSettings.meshtasticUsername + " has shared their position with you from node " + userLongName
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
typingMessage = "📍 " + userLongName + " has shared their position with you."
|
||||
}
|
||||
|
||||
|
||||
} label: {
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
|
||||
|
||||
ProgressView("\(NSLocalizedString("bytes", comment: "")): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ struct Contacts: View {
|
|||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@ObservedObject private var userSettings: UserSettings = UserSettings()
|
||||
|
||||
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(key: "longName", ascending: true)],
|
||||
animation: .default)
|
||||
|
||||
|
||||
private var users: FetchedResults<UserEntity>
|
||||
@State var node: NodeInfoEntity? = nil
|
||||
@State private var userSelection: UserEntity? = nil // Nothing selected by default.
|
||||
@State private var channelSelection: ChannelEntity? = nil // Nothing selected by default.
|
||||
@State var node: NodeInfoEntity?
|
||||
@State private var userSelection: UserEntity? // Nothing selected by default.
|
||||
@State private var channelSelection: ChannelEntity? // Nothing selected by default.
|
||||
@State private var isPresentingDeleteChannelMessagesConfirm: Bool = false
|
||||
@State private var isPresentingDeleteUserMessagesConfirm: Bool = false
|
||||
@State private var isPresentingTraceRouteSentAlert = false
|
||||
|
|
@ -38,7 +38,7 @@ struct Contacts: View {
|
|||
ForEach(node!.myInfo!.channels!.array as! [ChannelEntity], id: \.self) { (channel: ChannelEntity) in
|
||||
if channel.name?.lowercased() ?? "" != "admin" && channel.name?.lowercased() ?? "" != "gpio" && channel.name?.lowercased() ?? "" != "serial" {
|
||||
NavigationLink(destination: ChannelMessageList(channel: channel)) {
|
||||
|
||||
|
||||
let mostRecent = channel.allPrivateMessages.last(where: { $0.channel == channel.index })
|
||||
let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64((mostRecent?.messageTimestamp ?? 0 ))))
|
||||
let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0
|
||||
|
|
@ -60,7 +60,7 @@ struct Contacts: View {
|
|||
}
|
||||
Spacer()
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
VStack (alignment: .trailing) {
|
||||
VStack(alignment: .trailing) {
|
||||
if lastMessageDay == currentDay {
|
||||
Text(lastMessageTime, style: .time )
|
||||
.font(.subheadline)
|
||||
|
|
@ -102,7 +102,7 @@ struct Contacts: View {
|
|||
// Would rather not do this but the merge changes on
|
||||
// A single object is only working on mac GVH
|
||||
context.refreshAllObjects()
|
||||
//context.refresh(channel, mergeChanges: true)
|
||||
// context.refresh(channel, mergeChanges: true)
|
||||
} catch {
|
||||
context.rollback()
|
||||
print("💥 Save Channel Mute Error")
|
||||
|
|
@ -136,7 +136,7 @@ struct Contacts: View {
|
|||
}
|
||||
}
|
||||
.padding([.top, .bottom])
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Section(header: Text("direct.messages")) {
|
||||
|
|
@ -157,7 +157,7 @@ struct Contacts: View {
|
|||
Text(user.longName ?? NSLocalizedString("unknown", comment: "Unknown")).font(.headline)
|
||||
Spacer()
|
||||
if user.messageList.count > 0 {
|
||||
VStack (alignment: .trailing) {
|
||||
VStack(alignment: .trailing) {
|
||||
if lastMessageDay == currentDay {
|
||||
Text(lastMessageTime, style: .time )
|
||||
.font(.subheadline)
|
||||
|
|
@ -218,8 +218,7 @@ struct Contacts: View {
|
|||
.alert(
|
||||
"Trace Route Sent",
|
||||
isPresented: $isPresentingTraceRouteSentAlert
|
||||
)
|
||||
{
|
||||
) {
|
||||
Button("OK", role: .cancel) { }
|
||||
}
|
||||
message: {
|
||||
|
|
@ -264,15 +263,15 @@ struct Contacts: View {
|
|||
node = fetchedNode[0]
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
detail: {
|
||||
if let user = userSelection {
|
||||
UserMessageList(user:user)
|
||||
|
||||
UserMessageList(user: user)
|
||||
|
||||
} else {
|
||||
Text("select.contact")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct UserMessageList: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
enum Field: Hashable {
|
||||
case messageText
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ struct UserMessageList: View {
|
|||
@State private var deleteMessageId: Int64 = 0
|
||||
@State private var replyMessageId: Int64 = 0
|
||||
@State private var sendPositionWithMessage: Bool = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmss", options: 0, locale: Locale.current)
|
||||
|
|
@ -39,7 +39,7 @@ struct UserMessageList: View {
|
|||
ForEach( user.messageList ) { (message: MessageEntity) in
|
||||
if user.num != bleManager.connectedPeripheral?.num ?? -1 {
|
||||
let currentUser: Bool = (bleManager.connectedPeripheral?.num ?? 0 == message.fromUser?.num ?? -1 ? true : false)
|
||||
|
||||
|
||||
if message.replyID > 0 {
|
||||
let messageReply = user.messageList.first(where: { $0.messageId == message.replyID })
|
||||
HStack {
|
||||
|
|
@ -55,8 +55,8 @@ struct UserMessageList: View {
|
|||
.padding(.trailing)
|
||||
}
|
||||
}
|
||||
HStack (alignment: .top) {
|
||||
if currentUser { Spacer(minLength:50) }
|
||||
HStack(alignment: .top) {
|
||||
if currentUser { Spacer(minLength: 50) }
|
||||
if !currentUser {
|
||||
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.gray), circleSize: 44, fontSize: 14)
|
||||
.padding(.all, 5)
|
||||
|
|
@ -64,7 +64,7 @@ struct UserMessageList: View {
|
|||
}
|
||||
VStack(alignment: currentUser ? .trailing : .leading) {
|
||||
let markdownText: LocalizedStringKey = LocalizedStringKey.init(message.messagePayloadMarkdown ?? (message.messagePayload ?? "EMPTY MESSAGE"))
|
||||
|
||||
|
||||
let linkBlue = Color(red: 0.4627, green: 0.8392, blue: 1) /* #76d6ff */
|
||||
Text(markdownText)
|
||||
.tint(linkBlue)
|
||||
|
|
@ -73,7 +73,7 @@ struct UserMessageList: View {
|
|||
.background(currentUser ? .accentColor : Color(.gray))
|
||||
.cornerRadius(15)
|
||||
.contextMenu {
|
||||
VStack{
|
||||
VStack {
|
||||
Text("channel")+Text(": \(message.channel)")
|
||||
}
|
||||
Menu("tapback") {
|
||||
|
|
@ -83,7 +83,7 @@ struct UserMessageList: View {
|
|||
print("Sent \(tb.emojiString) Tapback")
|
||||
self.context.refresh(user, mergeChanges: true)
|
||||
} else { print("\(tb.emojiString) Tapback Failed") }
|
||||
|
||||
|
||||
}) {
|
||||
Text(tb.description)
|
||||
let image = tb.emojiString.image()
|
||||
|
|
@ -157,11 +157,11 @@ struct UserMessageList: View {
|
|||
Image(systemName: "trash")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let tapbacks = message.value(forKey: "tapbacks") as! [MessageEntity]
|
||||
if tapbacks.count > 0 {
|
||||
VStack (alignment: .trailing) {
|
||||
HStack {
|
||||
VStack(alignment: .trailing) {
|
||||
HStack {
|
||||
ForEach( tapbacks ) { (tapback: MessageEntity) in
|
||||
VStack {
|
||||
let image = tapback.messagePayload!.image(fontSize: 20)
|
||||
|
|
@ -198,7 +198,7 @@ struct UserMessageList: View {
|
|||
.padding(.bottom)
|
||||
.id(user.messageList.firstIndex(of: message))
|
||||
if !currentUser {
|
||||
Spacer(minLength:50)
|
||||
Spacer(minLength: 50)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
|
|
@ -231,7 +231,7 @@ struct UserMessageList: View {
|
|||
scrollView.scrollTo(user.messageList.last!.messageId)
|
||||
}
|
||||
})
|
||||
.onChange(of: user.messageList, perform: { messages in
|
||||
.onChange(of: user.messageList, perform: { _ in
|
||||
if user.messageList.count > 0 {
|
||||
scrollView.scrollTo(user.messageList.last!.messageId)
|
||||
}
|
||||
|
|
@ -243,13 +243,13 @@ struct UserMessageList: View {
|
|||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
|
||||
|
||||
if userSettings.meshtasticUsername.count > 0 {
|
||||
typingMessage = "📍 " + userSettings.meshtasticUsername + " has shared their position with you from node " + userLongName + " and requested a response with your position."
|
||||
} else {
|
||||
typingMessage = "📍 " + userLongName + " has shared their position and requested a response with your position."
|
||||
}
|
||||
|
||||
|
||||
} label: {
|
||||
Text("share.position")
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
|
|
@ -264,7 +264,7 @@ struct UserMessageList: View {
|
|||
.padding(.trailing)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
HStack(alignment: .top) {
|
||||
ZStack {
|
||||
let kbType = UIKeyboardType(rawValue: UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0)
|
||||
|
|
@ -293,13 +293,13 @@ struct UserMessageList: View {
|
|||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
|
||||
|
||||
if userSettings.meshtasticUsername.count > 0 {
|
||||
typingMessage = "📍 " + userSettings.meshtasticUsername + " has shared their position with you from node " + userLongName + " and requested a response with your position."
|
||||
} else {
|
||||
typingMessage = "📍 " + userLongName + " has shared their position and requested a response with your position."
|
||||
}
|
||||
|
||||
|
||||
} label: {
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
|
|
|||
|
|
@ -8,21 +8,21 @@ import SwiftUI
|
|||
import Charts
|
||||
|
||||
struct DeviceMetricsLog: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
@State private var isPresentingClearLogConfirm: Bool = false
|
||||
@State var isExporting = false
|
||||
@State var exportString = ""
|
||||
var node: NodeInfoEntity
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
let oneDayAgo = Calendar.current.date(byAdding: .day, value: -3, to: Date())
|
||||
let data = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0 && time !=nil && time >= %@", oneDayAgo! as CVarArg)) ?? []
|
||||
if data.count > 0 {
|
||||
GroupBox(label: Label("battery.level.trend", systemImage: "battery.100")) {
|
||||
GroupBox(label: Label("battery.level.trend", systemImage: "battery.100")) {
|
||||
Chart(data.array as! [TelemetryEntity], id: \.self) {
|
||||
LineMark(
|
||||
x: .value("Hour", $0.time!.formattedDate(format: "ha")),
|
||||
|
|
@ -39,15 +39,15 @@ struct DeviceMetricsLog: View {
|
|||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
//Add a table for mac and ipad
|
||||
// Add a table for mac and ipad
|
||||
Table(node.telemetries!.reversed() as! [TelemetryEntity]) {
|
||||
|
||||
|
||||
TableColumn("battery.level") { dm in
|
||||
if dm.metricsType == 0 {
|
||||
if dm.batteryLevel == 0 {
|
||||
Text("Powered")
|
||||
} else {
|
||||
|
||||
|
||||
Text("\(String(dm.batteryLevel))%")
|
||||
}
|
||||
}
|
||||
|
|
@ -73,10 +73,10 @@ struct DeviceMetricsLog: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
ScrollView {
|
||||
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1),
|
||||
GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1),
|
||||
|
|
@ -118,7 +118,7 @@ struct DeviceMetricsLog: View {
|
|||
.font(.caption)
|
||||
Text("\(String(format: "%.2f", dm.airUtilTx))%")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Text(dm.time?.formattedDate(format: dateFormatString) ?? "Unknown time")
|
||||
.font(.caption2)
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ struct DeviceMetricsLog: View {
|
|||
}
|
||||
}
|
||||
Button {
|
||||
exportString = TelemetryToCsvFile(telemetry: node.telemetries!.array as! [TelemetryEntity], metricsType: 0)
|
||||
exportString = telemetryToCsvFile(telemetry: node.telemetries!.array as! [TelemetryEntity], metricsType: 0)
|
||||
isExporting = true
|
||||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
|
|
@ -182,7 +182,7 @@ struct DeviceMetricsLog: View {
|
|||
if case .success = result {
|
||||
print("Device metrics log download succeeded.")
|
||||
self.isExporting = false
|
||||
|
||||
|
||||
} else {
|
||||
print("Device metrics log download failed: \(result).")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,24 +7,24 @@
|
|||
import SwiftUI
|
||||
|
||||
struct EnvironmentMetricsLog: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
@State private var isPresentingClearLogConfirm: Bool = false
|
||||
|
||||
|
||||
@State var isExporting = false
|
||||
@State var exportString = ""
|
||||
|
||||
|
||||
var node: NodeInfoEntity
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
//Add a table for mac and ipad
|
||||
// Add a table for mac and ipad
|
||||
Table(node.telemetries!.reversed() as! [TelemetryEntity]) {
|
||||
TableColumn("Temperature") { em in
|
||||
if em.metricsType == 1 {
|
||||
|
|
@ -72,7 +72,7 @@ struct EnvironmentMetricsLog: View {
|
|||
GridItem(spacing: 0)
|
||||
]
|
||||
LazyVGrid(columns: columns, alignment: .leading, spacing: 1) {
|
||||
|
||||
|
||||
GridRow {
|
||||
Text("Temp")
|
||||
.font(.caption)
|
||||
|
|
@ -91,11 +91,11 @@ struct EnvironmentMetricsLog: View {
|
|||
.fontWeight(.bold)
|
||||
}
|
||||
ForEach(node.telemetries!.reversed() as! [TelemetryEntity], id: \.self) { (em: TelemetryEntity) in
|
||||
|
||||
|
||||
if em.metricsType == 1 {
|
||||
|
||||
|
||||
GridRow {
|
||||
|
||||
|
||||
Text(em.temperature.formattedTemperature())
|
||||
.font(.caption)
|
||||
Text("\(String(format: "%.2f", em.relativeHumidity))")
|
||||
|
|
@ -116,7 +116,7 @@ struct EnvironmentMetricsLog: View {
|
|||
}
|
||||
}
|
||||
HStack {
|
||||
|
||||
|
||||
Button(role: .destructive) {
|
||||
isPresentingClearLogConfirm = true
|
||||
} label: {
|
||||
|
|
@ -134,11 +134,11 @@ struct EnvironmentMetricsLog: View {
|
|||
Button("Delete all environment metrics?", role: .destructive) {
|
||||
if clearTelemetry(destNum: node.num, metricsType: 1, context: context) {
|
||||
print("Clear Environment Metrics Log Failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
exportString = TelemetryToCsvFile(telemetry: node.telemetries!.array as! [TelemetryEntity], metricsType: 1)
|
||||
exportString = telemetryToCsvFile(telemetry: node.telemetries!.array as! [TelemetryEntity], metricsType: 1)
|
||||
isExporting = true
|
||||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import MapKit
|
|||
import CoreLocation
|
||||
|
||||
struct NodeDetail: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
||||
|
|
@ -29,28 +29,28 @@ struct NodeDetail: View {
|
|||
tileType: "png",
|
||||
canReplaceMapContent: true
|
||||
)
|
||||
|
||||
|
||||
var node: NodeInfoEntity
|
||||
|
||||
|
||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: false)],
|
||||
predicate: NSPredicate(
|
||||
format: "expire == nil || expire >= %@", Date() as NSDate
|
||||
), animation: .none)
|
||||
private var waypoints: FetchedResults<WaypointEntity>
|
||||
|
||||
|
||||
/// The current weather condition for the city.
|
||||
@State private var condition: WeatherCondition?
|
||||
@State private var temperature: Measurement<UnitTemperature>?
|
||||
@State private var humidity: Int?
|
||||
@State private var symbolName: String = "cloud.fill"
|
||||
|
||||
|
||||
@State private var attributionLink: URL?
|
||||
@State private var attributionLogo: URL?
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
let hwModelString = node.user?.hwModel ?? "UNSET"
|
||||
|
||||
|
||||
NavigationStack {
|
||||
GeometryReader { bounds in
|
||||
VStack {
|
||||
|
|
@ -75,12 +75,12 @@ struct NodeDetail: View {
|
|||
centerOnPositionsOnly: true,
|
||||
customMapOverlay: self.customMapOverlay,
|
||||
overlays: self.overlays
|
||||
|
||||
|
||||
)
|
||||
VStack (alignment: .leading) {
|
||||
VStack(alignment: .leading) {
|
||||
Spacer()
|
||||
HStack (alignment: .bottom, spacing: 1) {
|
||||
|
||||
HStack(alignment: .bottom, spacing: 1) {
|
||||
|
||||
Picker("Map Type", selection: $mapType) {
|
||||
ForEach(MeshMapType.allCases) { map in
|
||||
Text(map.description).tag(map.MKMapTypeValue())
|
||||
|
|
@ -92,8 +92,7 @@ struct NodeDetail: View {
|
|||
VStack {
|
||||
Label(temperature?.formatted(.measurement(width: .narrow)) ?? "??", systemImage: symbolName)
|
||||
.font(.caption)
|
||||
|
||||
|
||||
|
||||
Label("\(humidity ?? 0)%", systemImage: "humidity")
|
||||
.font(.caption2)
|
||||
}
|
||||
|
|
@ -122,7 +121,7 @@ struct NodeDetail: View {
|
|||
#endif
|
||||
.gesture(
|
||||
LongPressGesture(minimumDuration: 0.5)
|
||||
.onEnded { value in
|
||||
.onEnded { _ in
|
||||
showingForecast = true
|
||||
}
|
||||
)
|
||||
|
|
@ -137,7 +136,7 @@ struct NodeDetail: View {
|
|||
}
|
||||
.padding([.top], 20)
|
||||
}
|
||||
|
||||
|
||||
ScrollView {
|
||||
Divider()
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
|
|
@ -153,17 +152,17 @@ struct NodeDetail: View {
|
|||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 100, height: 100)
|
||||
.cornerRadius(5)
|
||||
|
||||
|
||||
Text(String(hwModelString))
|
||||
.foregroundColor(.gray)
|
||||
.font(.largeTitle).fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if node.snr > 0 {
|
||||
Divider()
|
||||
VStack(alignment: .center) {
|
||||
|
||||
|
||||
Image(systemName: "waveform.path")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
|
|
@ -176,15 +175,15 @@ struct NodeDetail: View {
|
|||
.fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if node.telemetries?.count ?? 0 >= 1 {
|
||||
|
||||
|
||||
let mostRecent = node.telemetries?.lastObject as! TelemetryEntity
|
||||
Divider()
|
||||
VStack(alignment: .center) {
|
||||
BatteryGauge(batteryLevel: Double(mostRecent.batteryLevel))
|
||||
if mostRecent.voltage > 0 {
|
||||
|
||||
|
||||
Text(String(format: "%.2f", mostRecent.voltage) + " V")
|
||||
.font(.title)
|
||||
.foregroundColor(.gray)
|
||||
|
|
@ -195,10 +194,10 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
|
||||
Divider()
|
||||
HStack(alignment: .center) {
|
||||
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "person")
|
||||
|
|
@ -207,7 +206,7 @@ struct NodeDetail: View {
|
|||
.symbolRenderingMode(.hierarchical)
|
||||
Text("user").font(.title)+Text(":").font(.title)
|
||||
}
|
||||
Text("!\(String(format:"%02x", node.num))")
|
||||
Text("!\(String(format: "%02x", node.num))")
|
||||
.font(.title).foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
|
|
@ -222,28 +221,28 @@ struct NodeDetail: View {
|
|||
Text(String(node.num)).font(.title).foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
VStack{
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "globe")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("MAC Address: ").font(.title)
|
||||
|
||||
|
||||
}
|
||||
Text(String(node.user?.macaddr?.macAddressString ?? "not a valid mac address"))
|
||||
.font(.title)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
VStack{
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "clock.badge.checkmark.fill")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("heard.last").font(.title)+Text(":").font(.title)
|
||||
|
||||
|
||||
}
|
||||
DateTimeText(dateTime: node.lastHeard)
|
||||
.font(.title3)
|
||||
|
|
@ -251,11 +250,11 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
Divider()
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
|
||||
VStack(alignment: .center) {
|
||||
CircleText(text: node.user?.shortName ?? "???", color: .accentColor)
|
||||
}
|
||||
|
|
@ -270,11 +269,11 @@ struct NodeDetail: View {
|
|||
.font(.callout).fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if node.snr > 0 {
|
||||
Divider()
|
||||
VStack(alignment: .center) {
|
||||
|
||||
|
||||
Image(systemName: "waveform.path")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
|
|
@ -286,14 +285,14 @@ struct NodeDetail: View {
|
|||
.fixedSize()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if node.telemetries?.count ?? 0 >= 1 {
|
||||
let mostRecent = node.telemetries?.lastObject as! TelemetryEntity
|
||||
Divider()
|
||||
VStack(alignment: .center) {
|
||||
BatteryGauge(batteryLevel: Double(mostRecent.batteryLevel))
|
||||
if mostRecent.voltage > 0 {
|
||||
|
||||
|
||||
Text(String(format: "%.2f", mostRecent.voltage) + " V")
|
||||
.font(.callout)
|
||||
.foregroundColor(.gray)
|
||||
|
|
@ -338,36 +337,36 @@ struct NodeDetail: View {
|
|||
.padding([.bottom], 10)
|
||||
Divider()
|
||||
}
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
|
||||
if (node.positions?.count ?? 0) > 0 {
|
||||
|
||||
|
||||
NavigationLink {
|
||||
PositionLog(node: node)
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "building.columns")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
|
||||
Text("Position Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Divider()
|
||||
}
|
||||
|
||||
|
||||
if (node.telemetries?.count ?? 0) > 0 {
|
||||
|
||||
|
||||
NavigationLink {
|
||||
DeviceMetricsLog(node: node)
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "flipphone")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
|
||||
Text("Device Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
|
|
@ -375,28 +374,28 @@ struct NodeDetail: View {
|
|||
NavigationLink {
|
||||
EnvironmentMetricsLog(node: node)
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "chart.xyaxis.line")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
|
||||
Text("Environment Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
if (self.bleManager.connectedPeripheral != nil && node.metadata != nil) {
|
||||
|
||||
|
||||
if self.bleManager.connectedPeripheral != nil && node.metadata != nil {
|
||||
|
||||
HStack {
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
|
||||
if node.metadata?.canShutdown ?? false || hwModelString == "RAK4631" {//node.metadata?.hwModel ?? "UNSET" == "RAK4631" {
|
||||
|
||||
if node.metadata?.canShutdown ?? false || hwModelString == "RAK4631" {// node.metadata?.hwModel ?? "UNSET" == "RAK4631" {
|
||||
|
||||
Button(action: {
|
||||
showingShutdownConfirm = true
|
||||
}) {
|
||||
|
||||
|
||||
Label("Power Off", systemImage: "power")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
|
|
@ -414,7 +413,7 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button(action: {
|
||||
showingRebootConfirm = true
|
||||
}) {
|
||||
|
|
@ -448,7 +447,7 @@ struct NodeDetail: View {
|
|||
.controlSize(.mini)
|
||||
}
|
||||
.frame(height: 15)
|
||||
|
||||
|
||||
Link("Other data sources", destination: attributionLink ?? URL(string: "https://weather-data.apple.com/legal-attribution.html")!)
|
||||
}
|
||||
.font(.footnote)
|
||||
|
|
@ -456,7 +455,7 @@ struct NodeDetail: View {
|
|||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea([.leading, .trailing])
|
||||
.sheet(isPresented: $presentingWaypointForm ) {//, onDismiss: didDismissSheet) {
|
||||
.sheet(isPresented: $presentingWaypointForm ) {// , onDismiss: didDismissSheet) {
|
||||
WaypointFormView(coordinate: waypointCoordinate ?? LocationHelper.DefaultLocation, waypointId: editingWaypoint)
|
||||
.presentationDetents([.medium, .large])
|
||||
.presentationDragIndicator(.automatic)
|
||||
|
|
@ -496,17 +495,17 @@ struct NodeDetail: View {
|
|||
}
|
||||
.task(id: node.num) {
|
||||
do {
|
||||
|
||||
|
||||
if node.positions?.count ?? 0 > 0 {
|
||||
|
||||
|
||||
let mostRecent = node.positions?.lastObject as! PositionEntity
|
||||
|
||||
|
||||
let weather = try await WeatherService.shared.weather(for: mostRecent.nodeLocation!)
|
||||
condition = weather.currentWeather.condition
|
||||
temperature = weather.currentWeather.temperature
|
||||
humidity = Int(weather.currentWeather.humidity * 100)
|
||||
symbolName = weather.currentWeather.symbolName
|
||||
|
||||
|
||||
let attribution = try await WeatherService.shared.attribution
|
||||
attributionLink = attribution.legalPageURL
|
||||
attributionLogo = colorScheme == .light ? attribution.combinedMarkLightURL : attribution.combinedMarkDarkURL
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ struct NodeList: View {
|
|||
|
||||
private var nodes: FetchedResults<NodeInfoEntity>
|
||||
|
||||
@State private var selection: NodeInfoEntity? = nil // Nothing selected by default.
|
||||
@State private var selection: NodeInfoEntity? // Nothing selected by default.
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationSplitView {
|
||||
List (nodes, id: \.self, selection: $selection) { node in
|
||||
List(nodes, id: \.self, selection: $selection) { node in
|
||||
if nodes.count == 0 {
|
||||
Text("no.nodes").font(.title)
|
||||
} else {
|
||||
|
|
@ -53,13 +53,13 @@ struct NodeList: View {
|
|||
HStack(alignment: .bottom) {
|
||||
let lastPostion = node.positions!.reversed()[0] as! PositionEntity
|
||||
let myCoord = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude)
|
||||
if lastPostion.nodeCoordinate != nil && myCoord.coordinate.longitude != LocationHelper.DefaultLocation.longitude && myCoord.coordinate.latitude != LocationHelper.DefaultLocation.latitude {
|
||||
if lastPostion.nodeCoordinate != nil && myCoord.coordinate.longitude != LocationHelper.DefaultLocation.longitude && myCoord.coordinate.latitude != LocationHelper.DefaultLocation.latitude {
|
||||
let nodeCoord = CLLocation(latitude: lastPostion.nodeCoordinate!.latitude, longitude: lastPostion.nodeCoordinate!.longitude)
|
||||
let metersAway = nodeCoord.distance(from: myCoord)
|
||||
Image(systemName: "lines.measurement.horizontal")
|
||||
.font(.title3)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
||||
|
||||
DistanceText(meters: metersAway).font(.subheadline)
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ struct NodeList: View {
|
|||
}
|
||||
} detail: {
|
||||
if let node = selection {
|
||||
NodeDetail(node:node)
|
||||
NodeDetail(node: node)
|
||||
} else {
|
||||
Text("select.node")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ struct NodeMap: View {
|
|||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
@AppStorage("meshMapCustomTileServer") var customTileServer: String = "" {
|
||||
didSet {
|
||||
if customTileServer == "" {
|
||||
|
|
@ -32,18 +32,18 @@ struct NodeMap: View {
|
|||
@AppStorage("meshMapType") private var meshMapType = "hybridFlyover"
|
||||
@AppStorage("meshMapUserTrackingMode") private var meshMapUserTrackingMode = 0
|
||||
@AppStorage("meshMapCenteringMode") private var meshMapCenteringMode = 0
|
||||
|
||||
//&& nodePosition != nil
|
||||
|
||||
// && nodePosition != nil
|
||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "time", ascending: true)],
|
||||
predicate: NSPredicate(format: "time >= %@ && nodePosition != nil", Calendar.current.startOfDay(for: Date()) as NSDate), animation: .none)
|
||||
private var positions: FetchedResults<PositionEntity>
|
||||
|
||||
|
||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: false)],
|
||||
predicate: NSPredicate(
|
||||
format: "expire == nil || expire >= %@", Date() as NSDate
|
||||
), animation: .none)
|
||||
private var waypoints: FetchedResults<WaypointEntity>
|
||||
|
||||
|
||||
@State private var mapType: MKMapType = .standard
|
||||
@State private var userTrackingMode: MKUserTrackingMode = .none
|
||||
@State private var mapCenteringMode: CenteringMode = .allAnnotations
|
||||
|
|
@ -56,12 +56,12 @@ struct NodeMap: View {
|
|||
canReplaceMapContent: true
|
||||
)
|
||||
@State private var overlays: [MapViewSwiftUI.Overlay] = []
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
|
||||
|
||||
MapViewSwiftUI(onLongPress: { coord in
|
||||
waypointCoordinate = coord
|
||||
editingWaypoint = 0
|
||||
|
|
@ -98,11 +98,11 @@ struct NodeMap: View {
|
|||
}
|
||||
.ignoresSafeArea(.all, edges: [.top, .leading, .trailing])
|
||||
.frame(maxHeight: .infinity)
|
||||
.sheet(isPresented: $presentingWaypointForm ) {//, onDismiss: didDismissSheet) {
|
||||
.sheet(isPresented: $presentingWaypointForm ) {// , onDismiss: didDismissSheet) {
|
||||
WaypointFormView(coordinate: waypointCoordinate, waypointId: editingWaypoint)
|
||||
.presentationDetents([.medium, .large])
|
||||
.presentationDragIndicator(.automatic)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.navigationBarItems(leading:
|
||||
|
|
@ -143,7 +143,7 @@ struct NodeMap: View {
|
|||
mapType = .hybridFlyover
|
||||
}
|
||||
})
|
||||
.onDisappear (perform: {
|
||||
.onDisappear(perform: {
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,25 +7,25 @@
|
|||
import SwiftUI
|
||||
|
||||
struct PositionLog: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
@State var isExporting = false
|
||||
@State var exportString = ""
|
||||
|
||||
|
||||
var node: NodeInfoEntity
|
||||
|
||||
|
||||
@State private var isPresentingClearLogConfirm = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
//Add a table for mac and ipad
|
||||
// Add a table for mac and ipad
|
||||
Table(node.positions!.reversed() as! [PositionEntity]) {
|
||||
TableColumn("SeqNo") { position in
|
||||
Text(String(position.seqNo))
|
||||
|
|
@ -55,9 +55,9 @@ struct PositionLog: View {
|
|||
Text(position.time?.formattedDate(format: dateFormatString) ?? NSLocalizedString("unknown.age", comment: ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
ScrollView {
|
||||
// Use a grid on iOS as a table only shows a single column
|
||||
let columns = [
|
||||
|
|
@ -68,9 +68,9 @@ struct PositionLog: View {
|
|||
GridItem(spacing: 0)
|
||||
]
|
||||
LazyVGrid(columns: columns, alignment: .leading, spacing: 1) {
|
||||
|
||||
|
||||
GridRow {
|
||||
|
||||
|
||||
Text("Latitude")
|
||||
.font(.caption2)
|
||||
.fontWeight(.bold)
|
||||
|
|
@ -125,20 +125,20 @@ struct PositionLog: View {
|
|||
Button("Delete all positions?", role: .destructive) {
|
||||
if clearPositions(destNum: node.num, context: context) {
|
||||
print("Successfully Cleared Position Log")
|
||||
|
||||
|
||||
} else {
|
||||
print("Clear Position Log Failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
|
||||
exportString = PositionToCsvFile(positions: node.positions!.array as! [PositionEntity])
|
||||
|
||||
exportString = positionToCsvFile(positions: node.positions!.array as! [PositionEntity])
|
||||
isExporting = true
|
||||
|
||||
|
||||
} label: {
|
||||
|
||||
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
|
|
@ -154,12 +154,12 @@ struct PositionLog: View {
|
|||
onCompletion: { result in
|
||||
|
||||
if case .success = result {
|
||||
|
||||
|
||||
print("Position log download succeeded.")
|
||||
self.isExporting = false
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
print("Position log download failed: \(result).")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ import SwiftUI
|
|||
import StoreKit
|
||||
|
||||
struct AboutMeshtastic: View {
|
||||
|
||||
|
||||
let locale = Locale.current
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack{
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
List {
|
||||
Section(header: Text("What is Meshtastic?")) {
|
||||
Text("An open source, off-grid, decentralized, mesh network built to run on affordable, low-power devices.")
|
||||
.font(.title3)
|
||||
|
||||
|
||||
}
|
||||
Section(header: Text("Apple Apps")) {
|
||||
Button("Review the app") {
|
||||
|
|
|
|||
|
|
@ -14,38 +14,38 @@ import MapKit
|
|||
import CoreLocation
|
||||
|
||||
struct AdminMessageList: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
var user: UserEntity?
|
||||
|
||||
|
||||
var body: some View {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmssa", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mm:ss a")
|
||||
List {
|
||||
if user != nil {
|
||||
|
||||
ForEach ( user!.adminMessageList.reversed() ) { am in
|
||||
|
||||
VStack (alignment: .leading) {
|
||||
|
||||
|
||||
ForEach( user!.adminMessageList.reversed() ) { am in
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
Text("\(am.adminDescription ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Text("Sent \(Date(timeIntervalSince1970: TimeInterval(am.messageTimestamp)).formattedDate(format: dateFormatString))")
|
||||
.foregroundColor(.gray)
|
||||
.font(.caption2)
|
||||
|
||||
HStack (spacing: 0) {
|
||||
|
||||
HStack(spacing: 0) {
|
||||
let ackErrorVal = RoutingError(rawValue: Int(am.ackError))
|
||||
|
||||
|
||||
if am.ackTimestamp > 0 {
|
||||
Text(ackErrorVal?.display ?? "Empty Ack Error")
|
||||
.foregroundColor(am.receivedACK ? .gray : .red)
|
||||
.font(.caption2)
|
||||
}
|
||||
|
||||
|
||||
if am.receivedACK && am.ackTimestamp > 0 {
|
||||
Text(" \(Date(timeIntervalSince1970: TimeInterval(am.ackTimestamp)).formattedDate(format: "h:mm:ss a"))")
|
||||
.foregroundColor(.gray)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ struct AppSettings: View {
|
|||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
@State private var isPresentingCoreDataResetConfirm = false
|
||||
@State private var preferredDeviceConnected = false
|
||||
|
||||
|
|
@ -28,32 +28,32 @@ struct AppSettings: View {
|
|||
.listRowSeparator(.visible)
|
||||
}
|
||||
Section(header: Text("options")) {
|
||||
|
||||
|
||||
Picker("keyboard.type", selection: $userSettings.keyboardType) {
|
||||
ForEach(KeyboardType.allCases) { kb in
|
||||
Text(kb.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("phone.gps")) {
|
||||
|
||||
|
||||
Toggle(isOn: $userSettings.provideLocation) {
|
||||
|
||||
Label("provide.location", systemImage: "location.circle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if userSettings.provideLocation {
|
||||
|
||||
|
||||
Picker("update.interval", selection: $userSettings.provideLocationInterval) {
|
||||
ForEach(LocationUpdateInterval.allCases) { lu in
|
||||
Text(lu.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
Text("phone.gps.interval.description")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
|
|
@ -68,27 +68,27 @@ struct AppSettings: View {
|
|||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("map options")) {
|
||||
|
||||
|
||||
Picker("map.type", selection: $userSettings.meshMapType) {
|
||||
ForEach(MeshMapType.allCases) { map in
|
||||
Text(map.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
if userSettings.meshMapUserTrackingMode == 0 {
|
||||
|
||||
|
||||
Picker("map.centering", selection: $userSettings.meshMapCenteringMode) {
|
||||
ForEach(CenteringMode.allCases) { cm in
|
||||
Text(cm.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
Toggle(isOn: $userSettings.meshMapRecentering) {
|
||||
|
||||
|
||||
Label("map.recentering", systemImage: "camera.metering.center.weighted")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
|
@ -126,8 +126,8 @@ struct AppSettings: View {
|
|||
.onAppear {
|
||||
self.bleManager.context = context
|
||||
}
|
||||
.onChange(of: userSettings.provideLocation) { newProvideLocation in
|
||||
|
||||
.onChange(of: userSettings.provideLocation) { _ in
|
||||
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
self.bleManager.sendWantConfig()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,14 @@ func generateChannelKey(size: Int) -> String {
|
|||
}
|
||||
|
||||
struct Channels: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
@Environment(\.sizeCategory) var sizeCategory
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State var hasChanges = false
|
||||
@State private var isPresentingEditView = false
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
|
|
@ -35,14 +34,14 @@ struct Channels: View {
|
|||
@State private var channelRole = 0
|
||||
@State private var uplink = false
|
||||
@State private var downlink = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationStack {
|
||||
List {
|
||||
if node != nil && node?.myInfo != nil {
|
||||
ForEach(node!.myInfo!.channels?.array as! [ChannelEntity], id: \.self) { (channel: ChannelEntity) in
|
||||
Button(action: {
|
||||
Button(action: {
|
||||
channelIndex = channel.index
|
||||
channelRole = Int(channel.role)
|
||||
channelKey = channel.psk?.base64EncodedString() ?? ""
|
||||
|
|
@ -87,7 +86,7 @@ struct Channels: View {
|
|||
}
|
||||
}
|
||||
if node?.myInfo?.channels?.array.count ?? 0 < 8 && node != nil {
|
||||
|
||||
|
||||
Button {
|
||||
let key = generateChannelKey(size: 32)
|
||||
channelName = ""
|
||||
|
|
@ -98,7 +97,7 @@ struct Channels: View {
|
|||
downlink = false
|
||||
hasChanges = false
|
||||
isPresentingEditView = true
|
||||
|
||||
|
||||
} label: {
|
||||
Label("Add Channel", systemImage: "plus.square")
|
||||
}
|
||||
|
|
@ -107,7 +106,7 @@ struct Channels: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
.sheet(isPresented: $isPresentingEditView) {
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Text("channel")
|
||||
.font(.largeTitle)
|
||||
|
|
@ -125,7 +124,7 @@ struct Channels: View {
|
|||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.disabled(channelRole == 1 && channelName.count > 0)
|
||||
.onChange(of: channelName, perform: { value in
|
||||
.onChange(of: channelName, perform: { _ in
|
||||
channelName = channelName.replacing(" ", with: "")
|
||||
let totalBytes = channelName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
|
|
@ -165,23 +164,23 @@ struct Channels: View {
|
|||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.small)
|
||||
}
|
||||
HStack (alignment: .top) {
|
||||
HStack(alignment: .top) {
|
||||
Text("Key")
|
||||
Spacer()
|
||||
TextField (
|
||||
TextField(
|
||||
"",
|
||||
text: $channelKey,
|
||||
axis: .vertical
|
||||
)
|
||||
.foregroundColor(Color.gray)
|
||||
.disabled(true)
|
||||
|
||||
|
||||
}
|
||||
.textSelection(.enabled)
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
if channelRole == 1 {
|
||||
Text("Primary").tag(1)
|
||||
} else{
|
||||
} else {
|
||||
Text("Disabled").tag(0)
|
||||
Text("Secondary").tag(2)
|
||||
}
|
||||
|
|
@ -193,13 +192,13 @@ struct Channels: View {
|
|||
Toggle("Downlink Enabled", isOn: $downlink)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
//.onSubmit {
|
||||
//validate(name: channelName)
|
||||
//}
|
||||
.onChange(of: channelName) { newName in
|
||||
// .onSubmit {
|
||||
// validate(name: channelName)
|
||||
// }
|
||||
.onChange(of: channelName) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { newKeySize in
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
|
|
@ -208,16 +207,16 @@ struct Channels: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKey) { newKey in
|
||||
.onChange(of: channelKey) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelRole) { newRole in
|
||||
.onChange(of: channelRole) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: uplink) { newUplink in
|
||||
.onChange(of: uplink) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: downlink) { newDownlink in
|
||||
.onChange(of: downlink) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
HStack {
|
||||
|
|
@ -231,7 +230,7 @@ struct Channels: View {
|
|||
channel.settings.psk = Data(base64Encoded: channelKey) ?? Data()
|
||||
channel.settings.uplinkEnabled = uplink
|
||||
channel.settings.downlinkEnabled = downlink
|
||||
|
||||
|
||||
} else {
|
||||
if channelIndex <= node!.myInfo!.channels?.count ?? 0 {
|
||||
let channelEntity = node!.myInfo!.channels?[Int(channelIndex)] as! ChannelEntity
|
||||
|
|
@ -246,9 +245,9 @@ struct Channels: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let adminMessageId = bleManager.saveChannel(channel: channel, fromUser: node!.user!, toUser: node!.user!)
|
||||
|
||||
|
||||
if adminMessageId > 0 {
|
||||
self.isPresentingEditView = false
|
||||
channelName = ""
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@
|
|||
import SwiftUI
|
||||
|
||||
struct BluetoothConfig: View {
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var enabled = true
|
||||
|
|
@ -22,43 +19,35 @@ struct BluetoothConfig: View {
|
|||
@State var fixedPin = "123456"
|
||||
@State var shortPin = false
|
||||
var pinLength: Int = 6
|
||||
|
||||
let numberFormatter: NumberFormatter = {
|
||||
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .none
|
||||
|
||||
return formatter
|
||||
}()
|
||||
|
||||
var body: some View {
|
||||
|
||||
Form {
|
||||
Section(header: Text("options")) {
|
||||
|
||||
Toggle(isOn: $enabled) {
|
||||
Label("enabled", systemImage: "antenna.radiowaves.left.and.right")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Picker("bluetooth.pairingmode", selection: $mode ) {
|
||||
ForEach(BluetoothModes.allCases) { bm in
|
||||
Text(bm.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
if mode == 1 {
|
||||
HStack {
|
||||
Label("bluetooth.mode.fixedpin", systemImage: "wallet.pass")
|
||||
TextField("bluetooth.mode.fixedpin", text: $fixedPin)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: fixedPin, perform: { value in
|
||||
.onChange(of: fixedPin, perform: { _ in
|
||||
// Don't let the first character be 0 because it will get stripped when saving a UInt32
|
||||
if fixedPin.first == "0" {
|
||||
fixedPin = fixedPin.replacing("0", with: "")
|
||||
}
|
||||
//Require that pin is no more than 6 numbers and no less than 6 numbers
|
||||
// Require that pin is no more than 6 numbers and no less than 6 numbers
|
||||
if fixedPin.utf8.count == pinLength {
|
||||
shortPin = false
|
||||
} else if fixedPin.utf8.count > pinLength {
|
||||
|
|
@ -80,7 +69,6 @@ struct BluetoothConfig: View {
|
|||
}
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.bluetoothConfig == nil)
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
} label: {
|
||||
|
|
@ -128,7 +116,6 @@ struct BluetoothConfig: View {
|
|||
self.mode = Int(node?.bluetoothConfig?.mode ?? 0)
|
||||
self.fixedPin = String(node?.bluetoothConfig?.fixedPin ?? 123456)
|
||||
self.hasChanges = false
|
||||
|
||||
// Need to request a BluetoothConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.bluetoothConfig == nil {
|
||||
print("empty bluetooth config")
|
||||
|
|
|
|||
|
|
@ -7,33 +7,33 @@
|
|||
import SwiftUI
|
||||
|
||||
struct DeviceConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingNodeDBResetConfirm = false
|
||||
@State private var isPresentingFactoryResetConfirm = false
|
||||
@State private var isPresentingSaveConfirm = false
|
||||
@State var hasChanges = false
|
||||
|
||||
|
||||
@State var deviceRole = 0
|
||||
@State var buzzerGPIO = 0
|
||||
@State var buttonGPIO = 0
|
||||
@State var serialEnabled = true
|
||||
@State var debugLogEnabled = false
|
||||
@State var rebroadcastMode = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
Form {
|
||||
|
||||
|
||||
Section(header: Text("options")) {
|
||||
|
||||
|
||||
Picker("Device Role", selection: $deviceRole ) {
|
||||
ForEach(DeviceRoles.allCases) { dr in
|
||||
Text(dr.name)
|
||||
|
|
@ -44,7 +44,7 @@ struct DeviceConfig: View {
|
|||
Text(DeviceRoles(rawValue: deviceRole)?.description ?? "")
|
||||
.foregroundColor(.gray)
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("Rebroadcast Mode", selection: $rebroadcastMode ) {
|
||||
ForEach(RebroadcastModes.allCases) { rm in
|
||||
Text(rm.name)
|
||||
|
|
@ -56,24 +56,24 @@ struct DeviceConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("Debug")) {
|
||||
|
||||
|
||||
Toggle(isOn: $serialEnabled) {
|
||||
|
||||
Label("Serial Console", systemImage: "terminal")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
Toggle(isOn: $debugLogEnabled) {
|
||||
|
||||
Label("Debug Log", systemImage: "ant.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("GPIO")) {
|
||||
|
||||
|
||||
Picker("Button GPIO", selection: $buttonGPIO) {
|
||||
ForEach(0..<40) {
|
||||
if $0 == 0 {
|
||||
|
|
@ -95,14 +95,14 @@ struct DeviceConfig: View {
|
|||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.deviceConfig == nil)
|
||||
|
||||
|
||||
// Only show these buttons for the BLE connected node
|
||||
if bleManager.connectedPeripheral != nil && node?.num ?? -1 == bleManager.connectedPeripheral.num {
|
||||
HStack {
|
||||
|
||||
|
||||
Button("Reset NodeDB", role: .destructive) {
|
||||
isPresentingNodeDBResetConfirm = true
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ struct DeviceConfig: View {
|
|||
titleVisibility: .visible
|
||||
) {
|
||||
Button("Erase all device and app data?", role: .destructive) {
|
||||
|
||||
|
||||
if bleManager.sendNodeDBReset(fromUser: node!.user!, toUser: node!.user!) {
|
||||
bleManager.disconnectPeripheral()
|
||||
clearCoreDataDatabase(context: context)
|
||||
|
|
@ -140,23 +140,23 @@ struct DeviceConfig: View {
|
|||
titleVisibility: .visible
|
||||
) {
|
||||
Button("Factory reset your device and app? ", role: .destructive) {
|
||||
|
||||
|
||||
if bleManager.sendFactoryReset(fromUser: node!.user!, toUser: node!.user!) {
|
||||
bleManager.disconnectPeripheral()
|
||||
clearCoreDataDatabase(context: context)
|
||||
} else {
|
||||
print("Factory Reset Failed")
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
|
||||
|
||||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ struct DeviceConfig: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
.confirmationDialog(
|
||||
|
||||
|
||||
"are.you.sure",
|
||||
isPresented: $isPresentingSaveConfirm,
|
||||
titleVisibility: .visible
|
||||
|
|
@ -182,7 +182,7 @@ struct DeviceConfig: View {
|
|||
dc.debugLogEnabled = debugLogEnabled
|
||||
dc.buttonGpio = UInt32(buttonGPIO)
|
||||
dc.buzzerGpio = UInt32(buzzerGPIO)
|
||||
|
||||
|
||||
let adminMessageId = bleManager.saveDeviceConfig(config: dc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
|
||||
if adminMessageId > 0 {
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
|
|
@ -212,7 +212,7 @@ struct DeviceConfig: View {
|
|||
self.buttonGPIO = Int(node?.deviceConfig?.buttonGpio ?? 0)
|
||||
self.buzzerGPIO = Int(node?.deviceConfig?.buzzerGpio ?? 0)
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a LoRaConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.deviceConfig == nil {
|
||||
print("empty device config")
|
||||
|
|
@ -223,37 +223,37 @@ struct DeviceConfig: View {
|
|||
}
|
||||
}
|
||||
.onChange(of: deviceRole) { newRole in
|
||||
|
||||
|
||||
if node != nil && node!.deviceConfig != nil {
|
||||
|
||||
|
||||
if newRole != node!.deviceConfig!.role { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: serialEnabled) { newSerial in
|
||||
|
||||
|
||||
if node != nil && node!.deviceConfig != nil {
|
||||
|
||||
|
||||
if newSerial != node!.deviceConfig!.serialEnabled { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: debugLogEnabled) { newDebugLog in
|
||||
|
||||
|
||||
if node != nil && node!.deviceConfig != nil {
|
||||
|
||||
|
||||
if newDebugLog != node!.deviceConfig!.debugLogEnabled { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: buttonGPIO) { newButtonGPIO in
|
||||
|
||||
|
||||
if node != nil && node!.deviceConfig != nil {
|
||||
|
||||
|
||||
if newButtonGPIO != node!.deviceConfig!.buttonGpio { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: buzzerGPIO) { newBuzzerGPIO in
|
||||
|
||||
|
||||
if node != nil && node!.deviceConfig != nil {
|
||||
|
||||
|
||||
if newBuzzerGPIO != node!.deviceConfig!.buttonGpio { hasChanges = true }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct DisplayConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
|
||||
|
|
@ -25,12 +25,12 @@ struct DisplayConfig: View {
|
|||
@State var flipScreen = false
|
||||
@State var oledType = 0
|
||||
@State var displayMode = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
Form {
|
||||
Section(header: Text("Device Screen")) {
|
||||
|
||||
|
||||
Picker("Display Mode", selection: $displayMode ) {
|
||||
ForEach(DisplayModes.allCases) { dm in
|
||||
Text(dm.description)
|
||||
|
|
@ -39,7 +39,7 @@ struct DisplayConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("Override automatic OLED screen detection.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Toggle(isOn: $compassNorthTop) {
|
||||
|
||||
Label("Always point north", systemImage: "location.north.circle")
|
||||
|
|
@ -47,7 +47,7 @@ struct DisplayConfig: View {
|
|||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("The compass heading on the screen outside of the circle will always point north.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Toggle(isOn: $flipScreen) {
|
||||
|
||||
Label("Flip Screen", systemImage: "pip.swap")
|
||||
|
|
@ -55,7 +55,7 @@ struct DisplayConfig: View {
|
|||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("Flip screen vertically")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("OLED Type", selection: $oledType ) {
|
||||
ForEach(OledTypes.allCases) { ot in
|
||||
Text(ot.description)
|
||||
|
|
@ -64,7 +64,7 @@ struct DisplayConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("Override automatic OLED screen detection.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
}
|
||||
Section(header: Text("Timing & Format")) {
|
||||
Picker("Screen on for", selection: $screenOnSeconds ) {
|
||||
|
|
@ -75,7 +75,7 @@ struct DisplayConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("How long the screen remains on after the user button is pressed or messages are received.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("Carousel Interval", selection: $screenCarouselInterval ) {
|
||||
ForEach(ScreenCarouselIntervals.allCases) { sci in
|
||||
Text(sci.description)
|
||||
|
|
@ -84,27 +84,27 @@ struct DisplayConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("Automatically toggles to the next page on the screen like a carousel, based the specified interval.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("GPS Format", selection: $gpsFormat ) {
|
||||
ForEach(GpsFormats.allCases) { lu in
|
||||
Text(lu.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
Text("The format used to display GPS coordinates on the device screen.")
|
||||
.font(.caption)
|
||||
.listRowSeparator(.visible)
|
||||
}
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.displayConfig == nil)
|
||||
|
||||
|
||||
Button {
|
||||
|
||||
|
||||
isPresentingSaveConfirm = true
|
||||
|
||||
|
||||
} label: {
|
||||
|
||||
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
|
||||
|
|
@ -129,10 +129,10 @@ struct DisplayConfig: View {
|
|||
dc.flipScreen = flipScreen
|
||||
dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue()
|
||||
dc.displaymode = DisplayModes(rawValue: displayMode)!.protoEnumValue()
|
||||
|
||||
|
||||
let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
|
||||
if adminMessageId > 0 {
|
||||
|
||||
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
// for now just disable the button after a successful save
|
||||
hasChanges = false
|
||||
|
|
@ -159,7 +159,7 @@ struct DisplayConfig: View {
|
|||
self.oledType = Int(node?.displayConfig?.oledType ?? 0)
|
||||
self.displayMode = Int(node?.displayConfig?.displayMode ?? 0)
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a LoRaConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.displayConfig == nil {
|
||||
print("empty display config")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct LoRaConfig: View {
|
||||
|
||||
|
||||
enum Field: Hashable {
|
||||
case channelNum
|
||||
}
|
||||
|
|
@ -20,14 +20,14 @@ struct LoRaConfig: View {
|
|||
formatter.groupingSeparator = ""
|
||||
return formatter
|
||||
}()
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
@FocusState var focusedField: Field?
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State var isPresentingSaveConfirm = false
|
||||
@State var hasChanges = false
|
||||
@State var region = 0
|
||||
|
|
@ -40,9 +40,9 @@ struct LoRaConfig: View {
|
|||
@State var bandwidth = 0
|
||||
@State var spreadFactor = 0
|
||||
@State var codingRate = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("Options")) {
|
||||
|
|
@ -54,15 +54,15 @@ struct LoRaConfig: View {
|
|||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
.fixedSize()
|
||||
|
||||
|
||||
Text("The region where you will be using your radios.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Toggle(isOn: $usePreset) {
|
||||
Label("Use Preset", systemImage: "list.bullet.rectangle")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
if usePreset {
|
||||
Picker("Presets", selection: $modemPreset ) {
|
||||
ForEach(ModemPresets.allCases) { m in
|
||||
|
|
@ -76,12 +76,12 @@ struct LoRaConfig: View {
|
|||
}
|
||||
}
|
||||
Section(header: Text("Advanced")) {
|
||||
|
||||
|
||||
Toggle(isOn: $txEnabled) {
|
||||
Label("Transmit Enabled", systemImage: "waveform.path")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
if !usePreset {
|
||||
HStack {
|
||||
Picker("Bandwidth", selection: $spreadFactor) {
|
||||
|
|
@ -124,7 +124,7 @@ struct LoRaConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("Sets the maximum number of hops, default is 3. Increasing hops also increases air time utilization and should be used carefully.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
HStack {
|
||||
Text("LoRa Channel Number")
|
||||
.fixedSize()
|
||||
|
|
@ -147,8 +147,7 @@ struct LoRaConfig: View {
|
|||
}
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil)
|
||||
|
||||
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
} label: {
|
||||
|
|
@ -198,7 +197,7 @@ struct LoRaConfig: View {
|
|||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
|
||||
self.bleManager.context = context
|
||||
self.hopLimit = Int(node?.loRaConfig?.hopLimit ?? 3)
|
||||
self.region = Int(node?.loRaConfig?.regionCode ?? 0)
|
||||
|
|
@ -211,14 +210,14 @@ struct LoRaConfig: View {
|
|||
self.codingRate = Int(node?.loRaConfig?.codingRate ?? 0)
|
||||
self.spreadFactor = Int(node?.loRaConfig?.spreadFactor ?? 0)
|
||||
print("Spreadum: \(self.spreadFactor)")
|
||||
|
||||
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a LoRaConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil {
|
||||
print("empty lora config")
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
|
||||
if node != nil && connectedNode != nil{
|
||||
if node != nil && connectedNode != nil {
|
||||
_ = bleManager.requestLoRaConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,14 @@
|
|||
import SwiftUI
|
||||
|
||||
struct CannedMessagesConfig: View {
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var hasMessagesChanges = false
|
||||
@State var configPreset = 0
|
||||
|
||||
@State var enabled = false
|
||||
/// CannedMessageModule will sends a bell character with the messages.
|
||||
@State var sendBell: Bool = false
|
||||
|
|
@ -38,29 +34,22 @@ struct CannedMessagesConfig: View {
|
|||
@State var inputbrokerEventCcw = 0
|
||||
/// Generate input event on Press of this kind.
|
||||
@State var inputbrokerEventPress = 0
|
||||
|
||||
@State var messages = ""
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack {
|
||||
|
||||
Form {
|
||||
|
||||
Section(header: Text("options")) {
|
||||
|
||||
Toggle(isOn: $enabled) {
|
||||
|
||||
Label("enabled", systemImage: "list.bullet.rectangle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $sendBell) {
|
||||
|
||||
Label("Send Bell", systemImage: "bell")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Picker("Configuration Presets", selection: $configPreset ) {
|
||||
ForEach(ConfigPresets.allCases) { cp in
|
||||
Text(cp.description)
|
||||
|
|
@ -69,26 +58,21 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
}
|
||||
|
||||
HStack {
|
||||
Label("Messages", systemImage: "message.fill")
|
||||
TextField("Messages separate with |", text: $messages, axis: .vertical)
|
||||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: messages, perform: { value in
|
||||
.onChange(of: messages, perform: { _ in
|
||||
|
||||
let totalBytes = messages.utf8.count
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 198 {
|
||||
|
||||
let firstNBytes = Data(messages.utf8.prefix(198))
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
// Set the shortName back to the last place where it was the right size
|
||||
messages = maxBytesString
|
||||
}
|
||||
|
|
@ -98,35 +82,27 @@ struct CannedMessagesConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
||||
Section(header: Text("Control Type")) {
|
||||
|
||||
|
||||
Toggle(isOn: $rotary1Enabled) {
|
||||
|
||||
Label("Rotary 1", systemImage: "dial.min")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(updown1Enabled)
|
||||
|
||||
Toggle(isOn: $updown1Enabled) {
|
||||
|
||||
Label("Up Down 1", systemImage: "arrow.up.arrow.down")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(rotary1Enabled)
|
||||
|
||||
}
|
||||
.disabled(configPreset > 0)
|
||||
Section(header: Text("Inputs")) {
|
||||
|
||||
Picker("Pin A", selection: $inputbrokerPinA) {
|
||||
ForEach(0..<40) {
|
||||
|
||||
if $0 == 0 {
|
||||
Text("unset")
|
||||
} else {
|
||||
|
||||
Text("Pin \($0)")
|
||||
}
|
||||
}
|
||||
|
|
@ -134,14 +110,11 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("GPIO pin for rotary encoder A port.")
|
||||
.font(.caption)
|
||||
|
||||
Picker("Pin B", selection: $inputbrokerPinB) {
|
||||
ForEach(0..<40) {
|
||||
|
||||
if $0 == 0 {
|
||||
Text("unset")
|
||||
} else {
|
||||
|
||||
Text("Pin \($0)")
|
||||
}
|
||||
}
|
||||
|
|
@ -149,14 +122,11 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("GPIO pin for rotary encoder B port.")
|
||||
.font(.caption)
|
||||
|
||||
Picker("Press Pin", selection: $inputbrokerPinPress) {
|
||||
ForEach(0..<40) {
|
||||
|
||||
if $0 == 0 {
|
||||
Text("unset")
|
||||
} else {
|
||||
|
||||
Text("Pin \($0)")
|
||||
}
|
||||
}
|
||||
|
|
@ -164,12 +134,9 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("GPIO pin for rotary encoder Press port.")
|
||||
.font(.caption)
|
||||
|
||||
}
|
||||
.disabled(configPreset > 0)
|
||||
|
||||
Section(header: Text("Key Mapping")) {
|
||||
|
||||
Picker("Clockwise Rotary Event", selection: $inputbrokerEventCw ) {
|
||||
ForEach(InputEventChars.allCases) { iec in
|
||||
Text(iec.description)
|
||||
|
|
@ -178,7 +145,6 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
Picker("Counter Clockwise Rotary Event", selection: $inputbrokerEventCcw ) {
|
||||
ForEach(InputEventChars.allCases) { iec in
|
||||
Text(iec.description)
|
||||
|
|
@ -187,7 +153,6 @@ struct CannedMessagesConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 10)
|
||||
|
||||
Picker("Encoder Press Event", selection: $inputbrokerEventPress ) {
|
||||
ForEach(InputEventChars.allCases) { iec in
|
||||
Text(iec.description)
|
||||
|
|
@ -201,10 +166,8 @@ struct CannedMessagesConfig: View {
|
|||
}
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.cannedMessageConfig == nil)
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
|
||||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
|
|
@ -287,7 +250,7 @@ struct CannedMessagesConfig: View {
|
|||
self.messages = node?.cannedMessageConfig?.messages ?? ""
|
||||
self.hasChanges = false
|
||||
self.hasMessagesChanges = false
|
||||
|
||||
|
||||
// Need to request a CannedMessagesModuleConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.cannedMessageConfig == nil {
|
||||
print("empty canned messages module config")
|
||||
|
|
@ -298,9 +261,9 @@ struct CannedMessagesConfig: View {
|
|||
}
|
||||
}
|
||||
.onChange(of: configPreset) { newPreset in
|
||||
|
||||
|
||||
if newPreset == 1 {
|
||||
|
||||
|
||||
// RAK Rotary Encoder
|
||||
updown1Enabled = true
|
||||
rotary1Enabled = false
|
||||
|
|
@ -310,9 +273,9 @@ struct CannedMessagesConfig: View {
|
|||
inputbrokerEventCw = InputEventChars.down.rawValue
|
||||
inputbrokerEventCcw = InputEventChars.up.rawValue
|
||||
inputbrokerEventPress = InputEventChars.select.rawValue
|
||||
|
||||
|
||||
} else if newPreset == 2 {
|
||||
|
||||
|
||||
// CardKB / RAK Keypad
|
||||
updown1Enabled = false
|
||||
rotary1Enabled = false
|
||||
|
|
@ -323,7 +286,7 @@ struct CannedMessagesConfig: View {
|
|||
inputbrokerEventCcw = InputEventChars.none.rawValue
|
||||
inputbrokerEventPress = InputEventChars.none.rawValue
|
||||
}
|
||||
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: enabled) { newEnabled in
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct ExternalNotificationConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var enabled = false
|
||||
|
|
@ -30,9 +30,9 @@ struct ExternalNotificationConfig: View {
|
|||
@State var outputVibra = 0
|
||||
@State var outputMilliseconds = 0
|
||||
@State var nagTimeout = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
Form {
|
||||
Section(header: Text("options")) {
|
||||
Toggle(isOn: $enabled) {
|
||||
|
|
@ -58,8 +58,7 @@ struct ExternalNotificationConfig: View {
|
|||
Section(header: Text("Primary GPIO")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
.textCase(.uppercase))
|
||||
{
|
||||
.textCase(.uppercase)) {
|
||||
Toggle(isOn: $active) {
|
||||
Label("Active", systemImage: "togglepower")
|
||||
}
|
||||
|
|
@ -93,12 +92,11 @@ struct ExternalNotificationConfig: View {
|
|||
Text("Specifies how long the monitored GPIO should output.")
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("Optional GPIO")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
.textCase(.uppercase))
|
||||
{
|
||||
.textCase(.uppercase)) {
|
||||
Toggle(isOn: $alertBellBuzzer) {
|
||||
Label("Alert GPIO buzzer when receiving a bell", systemImage: "bell")
|
||||
}
|
||||
|
|
@ -174,7 +172,7 @@ struct ExternalNotificationConfig: View {
|
|||
enc.outputMs = UInt32(outputMilliseconds)
|
||||
enc.usePwm = usePWM
|
||||
let adminMessageId = bleManager.saveExternalNotificationModuleConfig(config: enc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
|
||||
if adminMessageId > 0{
|
||||
if adminMessageId > 0 {
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
// for now just disable the button after a successful save
|
||||
hasChanges = false
|
||||
|
|
@ -208,7 +206,7 @@ struct ExternalNotificationConfig: View {
|
|||
self.nagTimeout = Int(node?.externalNotificationConfig?.nagTimeout ?? 0)
|
||||
self.usePWM = node?.externalNotificationConfig?.usePWM ?? false
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.externalNotificationConfig == nil {
|
||||
print("empty external notification module config")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MQTTConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
|
@ -20,9 +20,9 @@ struct MQTTConfig: View {
|
|||
@State var password = ""
|
||||
@State var encryptionEnabled = false
|
||||
@State var jsonEnabled = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
Form {
|
||||
Section(header: Text("options")) {
|
||||
Toggle(isOn: $enabled) {
|
||||
|
|
@ -30,7 +30,7 @@ struct MQTTConfig: View {
|
|||
Label("enabled", systemImage: "dot.radiowaves.right")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
Toggle(isOn: $encryptionEnabled) {
|
||||
|
||||
Label("Encryption Enabled", systemImage: "lock.icloud")
|
||||
|
|
@ -50,7 +50,7 @@ struct MQTTConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: address, perform: { value in
|
||||
.onChange(of: address, perform: { _ in
|
||||
let totalBytes = address.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 30 {
|
||||
|
|
@ -66,24 +66,24 @@ struct MQTTConfig: View {
|
|||
.keyboardType(.default)
|
||||
}
|
||||
.autocorrectionDisabled()
|
||||
|
||||
|
||||
HStack {
|
||||
Label("mqtt.username", systemImage: "person.text.rectangle")
|
||||
TextField("mqtt.username", text: $username)
|
||||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: username, perform: { value in
|
||||
.onChange(of: username, perform: { _ in
|
||||
|
||||
let totalBytes = username.utf8.count
|
||||
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 62 {
|
||||
|
||||
let firstNBytes = Data(username.utf8.prefix(62))
|
||||
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
|
||||
// Set the shortName back to the last place where it was the right size
|
||||
username = maxBytesString
|
||||
}
|
||||
|
|
@ -100,17 +100,17 @@ struct MQTTConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: password, perform: { value in
|
||||
.onChange(of: password, perform: { _ in
|
||||
|
||||
let totalBytes = password.utf8.count
|
||||
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 62 {
|
||||
|
||||
let firstNBytes = Data(password.utf8.prefix(62))
|
||||
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
|
||||
// Set the shortName back to the last place where it was the right size
|
||||
password = maxBytesString
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ struct MQTTConfig: View {
|
|||
}
|
||||
.scrollDismissesKeyboard(.interactively)
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.mqttConfig == nil)
|
||||
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
} label: {
|
||||
|
|
@ -182,7 +182,7 @@ struct MQTTConfig: View {
|
|||
self.encryptionEnabled = (node?.mqttConfig?.encryptionEnabled ?? false)
|
||||
self.jsonEnabled = (node?.mqttConfig?.jsonEnabled ?? false)
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.telemetryConfig == nil {
|
||||
print("empty mqtt module config")
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@
|
|||
import SwiftUI
|
||||
|
||||
struct RangeTestConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var enabled = false
|
||||
@State var sender = 0
|
||||
@State var save = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Form {
|
||||
|
|
@ -65,7 +65,7 @@ struct RangeTestConfig: View {
|
|||
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
|
||||
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
|
||||
Button(buttonText) {
|
||||
|
||||
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
|
||||
if connectedNode != nil {
|
||||
var rtc = ModuleConfig.RangeTestConfig()
|
||||
|
|
@ -96,7 +96,7 @@ struct RangeTestConfig: View {
|
|||
self.save = node?.rangeTestConfig?.save ?? false
|
||||
self.sender = Int(node?.rangeTestConfig?.sender ?? 0)
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a RangeTestModule Config from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.rangeTestConfig == nil {
|
||||
print("empty range test module config")
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
import SwiftUI
|
||||
|
||||
struct SerialConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
|
||||
|
||||
@State var enabled = false
|
||||
@State var echo = false
|
||||
@State var rxd = 0
|
||||
|
|
@ -24,21 +24,21 @@ struct SerialConfig: View {
|
|||
@State var baudRate = 0
|
||||
@State var timeout = 0
|
||||
@State var mode = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
Form {
|
||||
|
||||
|
||||
Section(header: Text("options")) {
|
||||
|
||||
|
||||
Toggle(isOn: $enabled) {
|
||||
|
||||
Label("enabled", systemImage: "terminal")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
Toggle(isOn: $echo) {
|
||||
|
||||
Label("echo", systemImage: "repeat")
|
||||
|
|
@ -46,14 +46,14 @@ struct SerialConfig: View {
|
|||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("If set, any packets you send will be echoed back to your device.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("Baud", selection: $baudRate ) {
|
||||
ForEach(SerialBaudRates.allCases) { sbr in
|
||||
Text(sbr.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
Picker("timeout", selection: $timeout ) {
|
||||
ForEach(SerialTimeoutIntervals.allCases) { sti in
|
||||
Text(sti.description)
|
||||
|
|
@ -62,7 +62,7 @@ struct SerialConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("The amount of time to wait before we consider your packet as done.")
|
||||
.font(.caption)
|
||||
|
||||
|
||||
Picker("mode", selection: $mode ) {
|
||||
ForEach(SerialModeTypes.allCases) { smt in
|
||||
Text(smt.description)
|
||||
|
|
@ -71,7 +71,7 @@ struct SerialConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
}
|
||||
Section(header: Text("GPIO")) {
|
||||
|
||||
|
||||
Picker("Receive data (rxd) GPIO pin", selection: $rxd) {
|
||||
ForEach(0..<40) {
|
||||
if $0 == 0 {
|
||||
|
|
@ -98,13 +98,13 @@ struct SerialConfig: View {
|
|||
}
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.serialConfig == nil)
|
||||
|
||||
|
||||
Button {
|
||||
|
||||
|
||||
isPresentingSaveConfirm = true
|
||||
|
||||
|
||||
} label: {
|
||||
|
||||
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
|
||||
|
|
@ -113,7 +113,7 @@ struct SerialConfig: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
.confirmationDialog(
|
||||
|
||||
|
||||
"are.you.sure",
|
||||
isPresented: $isPresentingSaveConfirm,
|
||||
titleVisibility: .visible
|
||||
|
|
@ -131,9 +131,9 @@ struct SerialConfig: View {
|
|||
sc.baud = SerialBaudRates(rawValue: baudRate)!.protoEnumValue()
|
||||
sc.timeout = UInt32(timeout)
|
||||
sc.mode = SerialModeTypes(rawValue: mode)!.protoEnumValue()
|
||||
|
||||
|
||||
let adminMessageId = bleManager.saveSerialModuleConfig(config: sc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
|
||||
|
||||
|
||||
if adminMessageId > 0 {
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
// for now just disable the button after a successful save
|
||||
|
|
@ -153,7 +153,7 @@ struct SerialConfig: View {
|
|||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
|
||||
self.bleManager.context = context
|
||||
self.enabled = node?.serialConfig?.enabled ?? false
|
||||
self.echo = node?.serialConfig?.echo ?? false
|
||||
|
|
@ -163,7 +163,7 @@ struct SerialConfig: View {
|
|||
self.timeout = Int(node?.serialConfig?.timeout ?? 0)
|
||||
self.mode = Int(node?.serialConfig?.mode ?? 0)
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a SerialModuleConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.serialConfig == nil {
|
||||
print("empty serial module config")
|
||||
|
|
@ -175,51 +175,51 @@ struct SerialConfig: View {
|
|||
|
||||
}
|
||||
.onChange(of: enabled) { newEnabled in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newEnabled != node!.serialConfig!.enabled { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: echo) { newEcho in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newEcho != node!.serialConfig!.echo { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: rxd) { newRxd in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newRxd != node!.serialConfig!.rxd { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: txd) { newTxd in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
if newTxd != node!.serialConfig!.txd { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: baudRate) { newBaud in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newBaud != node!.serialConfig!.baudRate { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: timeout) { newTimeout in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newTimeout != node!.serialConfig!.timeout { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: mode) { newMode in
|
||||
|
||||
|
||||
if node != nil && node!.serialConfig != nil {
|
||||
|
||||
|
||||
if newMode != node!.serialConfig!.mode { hasChanges = true }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct TelemetryConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var deviceUpdateInterval = 0
|
||||
|
|
@ -21,9 +21,9 @@ struct TelemetryConfig: View {
|
|||
@State var environmentMeasurementEnabled = false
|
||||
@State var environmentScreenEnabled = false
|
||||
@State var environmentDisplayFahrenheit = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("update.interval")) {
|
||||
|
|
@ -88,7 +88,7 @@ struct TelemetryConfig: View {
|
|||
tc.environmentMeasurementEnabled = environmentMeasurementEnabled
|
||||
tc.environmentScreenEnabled = environmentScreenEnabled
|
||||
tc.environmentDisplayFahrenheit = environmentDisplayFahrenheit
|
||||
let adminMessageId = bleManager.saveTelemetryModuleConfig(config: tc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
|
||||
let adminMessageId = bleManager.saveTelemetryModuleConfig(config: tc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
|
||||
if adminMessageId > 0 {
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
// for now just disable the button after a successful save
|
||||
|
|
@ -114,7 +114,7 @@ struct TelemetryConfig: View {
|
|||
self.environmentScreenEnabled = node?.telemetryConfig?.environmentScreenEnabled ?? false
|
||||
self.environmentDisplayFahrenheit = node?.telemetryConfig?.environmentDisplayFahrenheit ?? false
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.telemetryConfig == nil {
|
||||
print("empty telemetry module config")
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct NetworkConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges: Bool = false
|
||||
@State var wifiEnabled = false
|
||||
|
|
@ -24,13 +24,13 @@ struct NetworkConfig: View {
|
|||
@State var ntpServer = ""
|
||||
@State var ethEnabled = false
|
||||
@State var ethMode = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("WiFi Options (ESP32 Only)")) {
|
||||
|
||||
|
||||
Toggle(isOn: $wifiEnabled) {
|
||||
Label("enabled", systemImage: "wifi")
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ struct NetworkConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: wifiSsid, perform: { value in
|
||||
.onChange(of: wifiSsid, perform: { _ in
|
||||
let totalBytes = wifiSsid.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 32 {
|
||||
|
|
@ -51,7 +51,7 @@ struct NetworkConfig: View {
|
|||
wifiSsid = maxBytesString
|
||||
}
|
||||
}
|
||||
hasChanges = true
|
||||
hasChanges = true
|
||||
})
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ struct NetworkConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: wifiPsk, perform: { value in
|
||||
.onChange(of: wifiPsk, perform: { _ in
|
||||
let totalBytes = wifiPsk.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 63 {
|
||||
|
|
@ -117,8 +117,8 @@ struct NetworkConfig: View {
|
|||
network.wifiSsid = self.wifiSsid
|
||||
network.wifiPsk = self.wifiPsk
|
||||
network.ethEnabled = self.ethEnabled
|
||||
//network.addressMode = Config.NetworkConfig.AddressMode.dhcp
|
||||
|
||||
// network.addressMode = Config.NetworkConfig.AddressMode.dhcp
|
||||
|
||||
let adminMessageId = bleManager.saveNetworkConfig(config: network, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
|
||||
if adminMessageId > 0 {
|
||||
// Should show a saved successfully alert once I know that to be true
|
||||
|
|
@ -145,7 +145,7 @@ struct NetworkConfig: View {
|
|||
self.wifiMode = Int(node?.networkConfig?.wifiMode ?? 0)
|
||||
self.ethEnabled = node?.networkConfig?.ethEnabled ?? false
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a NetworkConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
|
||||
print("empty network config")
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@
|
|||
|
||||
import SwiftUI
|
||||
|
||||
struct PositionFlags: OptionSet
|
||||
{
|
||||
struct PositionFlags: OptionSet {
|
||||
let rawValue: Int
|
||||
|
||||
|
||||
static let Altitude = PositionFlags(rawValue: 1)
|
||||
static let AltitudeMsl = PositionFlags(rawValue: 2)
|
||||
static let GeoidalSeparation = PositionFlags(rawValue: 4)
|
||||
|
|
@ -24,17 +23,17 @@ struct PositionFlags: OptionSet
|
|||
}
|
||||
|
||||
struct PositionConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
@State var hasFlagChanges = false
|
||||
|
||||
|
||||
@State var smartPositionEnabled = true
|
||||
@State var deviceGpsEnabled = true
|
||||
@State var fixedPosition = false
|
||||
|
|
@ -42,7 +41,7 @@ struct PositionConfig: View {
|
|||
@State var gpsAttemptTime = 0
|
||||
@State var positionBroadcastSeconds = 0
|
||||
@State var positionFlags = 3
|
||||
|
||||
|
||||
/// Position Flags
|
||||
/// Altitude value - 1
|
||||
@State var includeAltitude = false
|
||||
|
|
@ -68,9 +67,9 @@ struct PositionConfig: View {
|
|||
/// Intended for use with vehicle not walking speeds
|
||||
/// walking speeds are likely to be error prone like the compass
|
||||
@State var includeHeading = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("Device GPS")) {
|
||||
|
|
@ -103,36 +102,36 @@ struct PositionConfig: View {
|
|||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("Position Packet")) {
|
||||
|
||||
|
||||
Toggle(isOn: $smartPositionEnabled) {
|
||||
|
||||
Label("Smart Position Broadcast", systemImage: "location.fill.viewfinder")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
Picker("Position Broadcast Interval", selection: $positionBroadcastSeconds) {
|
||||
ForEach(UpdateIntervals.allCases) { at in
|
||||
Text(at.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
|
||||
Text("We should send our position this often (but only if it has changed significantly)")
|
||||
.font(.caption)
|
||||
}
|
||||
Section(header: Text("Position Flags")) {
|
||||
|
||||
|
||||
Text("Optional fields to include when assembling position messages. the more fields are included, the larger the message will be - leading to longer airtime and a higher risk of packet loss")
|
||||
.font(.caption)
|
||||
.listRowSeparator(.visible)
|
||||
|
||||
|
||||
Toggle(isOn: $includeAltitude) {
|
||||
Label("Altitude", systemImage: "arrow.up")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
if includeAltitude {
|
||||
Toggle(isOn: $includeAltitudeMsl) {
|
||||
Label("Altitude is Mean Sea Level", systemImage: "arrow.up.to.line.compact")
|
||||
|
|
@ -143,40 +142,40 @@ struct PositionConfig: View {
|
|||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
|
||||
|
||||
Toggle(isOn: $includeSatsinview) {
|
||||
Label("Number of satellites", systemImage: "skew")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $includeSeqNo) { //64
|
||||
|
||||
Toggle(isOn: $includeSeqNo) { // 64
|
||||
Label("Sequence number", systemImage: "number")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $includeTimestamp) { //128
|
||||
|
||||
Toggle(isOn: $includeTimestamp) { // 128
|
||||
Label("timestamp", systemImage: "clock")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $includeHeading) { //128
|
||||
|
||||
Toggle(isOn: $includeHeading) { // 128
|
||||
Label("Vehicle heading", systemImage: "location.circle")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $includeSpeed) { //128
|
||||
|
||||
Toggle(isOn: $includeSpeed) { // 128
|
||||
|
||||
Label("Vehicle speed", systemImage: "speedometer")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
Section(header: Text("Advanced Position Flags")) {
|
||||
|
||||
|
||||
Toggle(isOn: $includeDop) {
|
||||
Text("Dilution of precision (DOP) PDOP used by default")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
if includeDop {
|
||||
Toggle(isOn: $includeHvdop) {
|
||||
Text("If DOP is set use, HDOP / VDOP values instead of PDOP")
|
||||
|
|
@ -186,7 +185,7 @@ struct PositionConfig: View {
|
|||
}
|
||||
}
|
||||
.disabled(self.bleManager.connectedPeripheral == nil || node?.positionConfig == nil)
|
||||
|
||||
|
||||
Button {
|
||||
isPresentingSaveConfirm = true
|
||||
} label: {
|
||||
|
|
@ -205,12 +204,12 @@ struct PositionConfig: View {
|
|||
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
|
||||
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
|
||||
Button(buttonText) {
|
||||
|
||||
|
||||
if fixedPosition {
|
||||
_ = bleManager.sendPosition(destNum: node!.num, wantResponse: true)
|
||||
}
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
|
||||
|
||||
|
||||
if connectedNode != nil {
|
||||
var pc = Config.PositionConfig()
|
||||
pc.positionBroadcastSmartEnabled = smartPositionEnabled
|
||||
|
|
@ -219,7 +218,7 @@ struct PositionConfig: View {
|
|||
pc.gpsUpdateInterval = UInt32(gpsUpdateInterval)
|
||||
pc.gpsAttemptTime = UInt32(gpsAttemptTime)
|
||||
pc.positionBroadcastSecs = UInt32(positionBroadcastSeconds)
|
||||
var pf : PositionFlags = []
|
||||
var pf: PositionFlags = []
|
||||
if includeAltitude { pf.insert(.Altitude) }
|
||||
if includeAltitudeMsl { pf.insert(.AltitudeMsl) }
|
||||
if includeGeoidalSeparation { pf.insert(.GeoidalSeparation) }
|
||||
|
|
@ -253,7 +252,7 @@ struct PositionConfig: View {
|
|||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
|
||||
self.bleManager.context = context
|
||||
self.smartPositionEnabled = node?.positionConfig?.smartPositionEnabled ?? true
|
||||
self.deviceGpsEnabled = node?.positionConfig?.deviceGpsEnabled ?? true
|
||||
|
|
@ -262,9 +261,9 @@ struct PositionConfig: View {
|
|||
self.gpsAttemptTime = Int(node?.positionConfig?.gpsAttemptTime ?? 30)
|
||||
self.positionBroadcastSeconds = Int(node?.positionConfig?.positionBroadcastSeconds ?? 900)
|
||||
self.positionFlags = Int(node?.positionConfig?.positionFlags ?? 3)
|
||||
|
||||
|
||||
let pf = PositionFlags(rawValue: self.positionFlags)
|
||||
|
||||
|
||||
if pf.contains(.Altitude) { self.includeAltitude = true } else { self.includeAltitude = false }
|
||||
if pf.contains(.AltitudeMsl) { self.includeAltitudeMsl = true } else { self.includeAltitudeMsl = false }
|
||||
if pf.contains(.GeoidalSeparation) { self.includeGeoidalSeparation = true } else { self.includeGeoidalSeparation = false }
|
||||
|
|
@ -275,9 +274,9 @@ struct PositionConfig: View {
|
|||
if pf.contains(.Timestamp) { self.includeTimestamp = true } else { self.includeTimestamp = false }
|
||||
if pf.contains(.Speed) { self.includeSpeed = true } else { self.includeSpeed = false }
|
||||
if pf.contains(.Heading) { self.includeHeading = true } else { self.includeHeading = false }
|
||||
|
||||
|
||||
self.hasChanges = false
|
||||
|
||||
|
||||
// Need to request a PositionConfig from the remote node before allowing changes
|
||||
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
|
||||
print("empty position config")
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ struct MeshLog: View {
|
|||
@State private var document: LogDocument = LogDocument(logFile: "MESHTASTIC MESH ACTIVITY LOG\n")
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
List(logs, id: \.self, rowContent: Text.init)
|
||||
.task {
|
||||
do {
|
||||
|
|
@ -55,7 +55,7 @@ struct MeshLog: View {
|
|||
)
|
||||
.textSelection(.enabled)
|
||||
.font(.caption)
|
||||
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
Button(role: .destructive) {
|
||||
|
|
@ -74,7 +74,7 @@ struct MeshLog: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
Spacer()
|
||||
|
||||
|
||||
Button {
|
||||
isExporting = true
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
import SwiftUI
|
||||
|
||||
struct SaveChannelQRCode: View {
|
||||
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
|
||||
var channelSetLink: String
|
||||
var bleManager: BLEManager
|
||||
@State var connectedToDevice = false
|
||||
|
|
@ -22,15 +22,15 @@ struct SaveChannelQRCode: View {
|
|||
.foregroundColor(.gray)
|
||||
.font(.callout)
|
||||
.padding()
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
|
||||
Button {
|
||||
let success = bleManager.saveChannelSet(base64UrlString: channelSetLink)
|
||||
if success {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
||||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
|
|
@ -39,13 +39,13 @@ struct SaveChannelQRCode: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
.disabled(!connectedToDevice)
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Button {
|
||||
dismiss()
|
||||
} label: {
|
||||
Label("cancel", systemImage: "xmark")
|
||||
|
||||
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import SwiftUI
|
||||
|
||||
struct Settings: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
|
@ -17,9 +17,9 @@ struct Settings: View {
|
|||
@State private var selectedNode: Int = 0
|
||||
@State private var connectedNodeNum: Int = 0
|
||||
@State private var initialLoad: Bool = true
|
||||
|
||||
|
||||
@State private var selection: SettingsSidebar = .about
|
||||
|
||||
|
||||
enum SettingsSidebar {
|
||||
case appSettings
|
||||
case shareChannels
|
||||
|
|
@ -41,11 +41,11 @@ struct Settings: View {
|
|||
case adminMessageLog
|
||||
case about
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List {
|
||||
NavigationLink() {
|
||||
NavigationLink {
|
||||
AppSettings()
|
||||
} label: {
|
||||
Image(systemName: "gearshape")
|
||||
|
|
@ -80,10 +80,10 @@ struct Settings: View {
|
|||
let node = nodes.first(where: { $0.num == newValue })
|
||||
let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
|
||||
|
||||
if node?.metadata == nil {
|
||||
let adminMessageId = bleManager.requestDeviceMetadata(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode!.myInfo!.adminIndex, context: context)
|
||||
|
||||
|
||||
if adminMessageId > 0 {
|
||||
print("Sent node metadata request from node details")
|
||||
}
|
||||
|
|
@ -92,9 +92,9 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section("radio.configuration") {
|
||||
|
||||
|
||||
NavigationLink {
|
||||
ShareChannels(node: nodes.first(where: { $0.num == connectedNodeNum }))
|
||||
} label: {
|
||||
|
|
@ -104,18 +104,18 @@ struct Settings: View {
|
|||
}
|
||||
.tag(SettingsSidebar.shareChannels)
|
||||
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
UserConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "person.crop.rectangle.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("user")
|
||||
}
|
||||
.tag(SettingsSidebar.userConfig)
|
||||
|
||||
NavigationLink() {
|
||||
|
||||
NavigationLink {
|
||||
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
Image(systemName: "dot.radiowaves.left.and.right")
|
||||
|
|
@ -123,8 +123,8 @@ struct Settings: View {
|
|||
Text("lora")
|
||||
}
|
||||
.tag(SettingsSidebar.loraConfig)
|
||||
|
||||
NavigationLink() {
|
||||
|
||||
NavigationLink {
|
||||
Channels(node: nodes.first(where: { $0.num == connectedNodeNum }))
|
||||
} label: {
|
||||
Image(systemName: "fibrechannel")
|
||||
|
|
@ -133,8 +133,8 @@ struct Settings: View {
|
|||
}
|
||||
.tag(SettingsSidebar.channelConfig)
|
||||
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
|
||||
|
||||
NavigationLink() {
|
||||
|
||||
NavigationLink {
|
||||
BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
|
|
@ -142,7 +142,7 @@ struct Settings: View {
|
|||
Text("bluetooth")
|
||||
}
|
||||
.tag(SettingsSidebar.bluetoothConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
DeviceConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -151,7 +151,7 @@ struct Settings: View {
|
|||
Text("device")
|
||||
}
|
||||
.tag(SettingsSidebar.deviceConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
DisplayConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -160,30 +160,30 @@ struct Settings: View {
|
|||
Text("display")
|
||||
}
|
||||
.tag(SettingsSidebar.displayConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
NetworkConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "network")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("network")
|
||||
}
|
||||
.tag(SettingsSidebar.networkConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
PositionConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
||||
|
||||
Image(systemName: "location")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("position")
|
||||
}
|
||||
.tag(SettingsSidebar.positionConfig)
|
||||
|
||||
|
||||
}
|
||||
Section("module.configuration") {
|
||||
|
||||
|
||||
NavigationLink {
|
||||
CannedMessagesConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -194,7 +194,7 @@ struct Settings: View {
|
|||
Text("canned.messages")
|
||||
}
|
||||
.tag(SettingsSidebar.cannedMessagesConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
ExternalNotificationConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -203,7 +203,7 @@ struct Settings: View {
|
|||
Text("external.notification")
|
||||
}
|
||||
.tag(SettingsSidebar.externalNotificationConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
MQTTConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -212,7 +212,7 @@ struct Settings: View {
|
|||
Text("mqtt")
|
||||
}
|
||||
.tag(SettingsSidebar.mqttConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
RangeTestConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -221,7 +221,7 @@ struct Settings: View {
|
|||
Text("range.test")
|
||||
}
|
||||
.tag(SettingsSidebar.rangeTestConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
SerialConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -230,7 +230,7 @@ struct Settings: View {
|
|||
Text("serial")
|
||||
}
|
||||
.tag(SettingsSidebar.serialConfig)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
TelemetryConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -249,7 +249,7 @@ struct Settings: View {
|
|||
Text("mesh.log")
|
||||
}
|
||||
.tag(SettingsSidebar.meshLog)
|
||||
|
||||
|
||||
NavigationLink {
|
||||
let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
AdminMessageList(user: connectedNode?.user)
|
||||
|
|
@ -266,7 +266,7 @@ struct Settings: View {
|
|||
} label: {
|
||||
Image(systemName: "questionmark.app")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
||||
|
||||
Text("about.meshtastic")
|
||||
}
|
||||
.tag(SettingsSidebar.about)
|
||||
|
|
@ -280,7 +280,7 @@ struct Settings: View {
|
|||
selectedNode = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
initialLoad = false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.listStyle(GroupedListStyle())
|
||||
.navigationTitle("settings")
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ import CoreImage.CIFilterBuiltins
|
|||
|
||||
struct QrCodeImage {
|
||||
let context = CIContext()
|
||||
|
||||
|
||||
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")
|
||||
|
||||
|
||||
let transform = CGAffineTransform(scaleX: 20, y: 20)
|
||||
if let outputImage = filter.outputImage?.transformed(by: transform) {
|
||||
if let image = context.createCGImage(
|
||||
|
|
@ -30,7 +30,7 @@ struct QrCodeImage {
|
|||
}
|
||||
|
||||
struct ShareChannels: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
|
@ -47,13 +47,13 @@ struct ShareChannels: View {
|
|||
var node: NodeInfoEntity?
|
||||
@State private var channelsUrl = "https://www.meshtastic.org/e/#"
|
||||
var qrCodeImage = QrCodeImage()
|
||||
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { bounds in
|
||||
let smallest = min(bounds.size.width, bounds.size.height)
|
||||
ScrollView {
|
||||
if node != nil && node?.myInfo != nil {
|
||||
Grid() {
|
||||
Grid {
|
||||
GridRow {
|
||||
Spacer()
|
||||
Text("include")
|
||||
|
|
@ -195,7 +195,7 @@ struct ShareChannels: View {
|
|||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
|
||||
|
||||
Image(uiImage: qrImage)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
|
|
@ -227,21 +227,21 @@ struct ShareChannels: View {
|
|||
Text("Primary Channel").font(.title2)
|
||||
Text("The first channel is the Primary channel and is where much of the mesh activity takes place. DM's are only available on the primary channel and it can not be disabled.")
|
||||
.font(.callout)
|
||||
.padding([.leading,.trailing,.bottom])
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
Text("Admin Channel").font(.title2)
|
||||
Text("A channel with the name 'admin' is the Admin channel and can be used to remotely administer nodes on your mesh, text messages can not be sent over the admin channel.")
|
||||
.font(.callout)
|
||||
.padding([.leading,.trailing,.bottom])
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
Text("Private Channels").font(.title2)
|
||||
Text("The other channels can be used for private group converations. Each of these groups has its own encryption key.")
|
||||
.font(.callout)
|
||||
.padding([.leading,.trailing,.bottom])
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
Divider()
|
||||
}
|
||||
.padding()
|
||||
.presentationDetents([.large])
|
||||
.presentationDragIndicator(.automatic)
|
||||
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Button {
|
||||
isPresentingHelp = false
|
||||
|
|
@ -264,13 +264,13 @@ struct ShareChannels: View {
|
|||
bleManager.context = context
|
||||
GenerateChannelSet()
|
||||
}
|
||||
.onChange(of: includeChannel1) { includeCh1 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel2) { includeCh2 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel3) { includeCh3 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel4) { includeCh4 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel5) { includeCh5 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel6) { includeCh6 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel7) { includeCh7 in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel1) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel2) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel3) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel4) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel5) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel6) { _ in GenerateChannelSet() }
|
||||
.onChange(of: includeChannel7) { _ in GenerateChannelSet() }
|
||||
}
|
||||
}
|
||||
func GenerateChannelSet() {
|
||||
|
|
@ -291,10 +291,10 @@ struct ShareChannels: View {
|
|||
if node?.myInfo?.channels != nil && node?.myInfo?.channels?.count ?? 0 > 0 {
|
||||
for ch in node!.myInfo!.channels!.array as! [ChannelEntity] {
|
||||
if ch.role > 0 {
|
||||
|
||||
|
||||
if ch.index == 0 && includeChannel0 || ch.index == 1 && includeChannel1 || ch.index == 2 && includeChannel2 || ch.index == 3 && includeChannel3 ||
|
||||
ch.index == 4 && includeChannel4 || ch.index == 5 && includeChannel5 || ch.index == 6 && includeChannel6 || ch.index == 7 && includeChannel7 {
|
||||
|
||||
ch.index == 4 && includeChannel4 || ch.index == 5 && includeChannel5 || ch.index == 6 && includeChannel6 || ch.index == 7 && includeChannel7 {
|
||||
|
||||
var channelSettings = ChannelSettings()
|
||||
channelSettings.name = ch.name!
|
||||
channelSettings.psk = ch.psk!
|
||||
|
|
|
|||
|
|
@ -8,17 +8,17 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct UserConfig: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@Environment(\.dismiss) private var goBack
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
enum Field: Hashable {
|
||||
case frequencyOverride
|
||||
}
|
||||
|
||||
|
||||
@State private var isPresentingFactoryResetConfirm: Bool = false
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var hasChanges = false
|
||||
|
|
@ -28,24 +28,24 @@ struct UserConfig: View {
|
|||
@State var overrideDutyCycle = false
|
||||
@State var overrideFrequency: Float = 0.0
|
||||
@State var txPower = 0
|
||||
|
||||
|
||||
@FocusState var focusedField: Field?
|
||||
|
||||
|
||||
let floatFormatter: NumberFormatter = {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .decimal
|
||||
return formatter
|
||||
}()
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("User Details")) {
|
||||
HStack {
|
||||
Label(isLicensed ? "Call Sign" : "Long Name", systemImage: "person.crop.rectangle.fill")
|
||||
TextField("Long Name", text: $longName)
|
||||
.onChange(of: longName, perform: { value in
|
||||
.onChange(of: longName, perform: { _ in
|
||||
let totalBytes = longName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > (isLicensed ? 8 : 36) {
|
||||
|
|
@ -61,12 +61,12 @@ struct UserConfig: View {
|
|||
.disableAutocorrection(true)
|
||||
Text("\(String(isLicensed ? "Call Sign" : "Long Name")) can be up to \(isLicensed ? "8" : "36") bytes long.")
|
||||
.font(.caption2)
|
||||
|
||||
|
||||
HStack {
|
||||
Label("Short Name", systemImage: "circlebadge.fill")
|
||||
TextField("Short Name", text: $shortName)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: shortName, perform: { value in
|
||||
.onChange(of: shortName, perform: { _ in
|
||||
let totalBytes = shortName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 4 {
|
||||
|
|
@ -83,20 +83,20 @@ struct UserConfig: View {
|
|||
.disableAutocorrection(true)
|
||||
Text("The last 4 of the device MAC address will be appended to the short name to set the device's BLE Name. Short name can be up to 4 bytes long.")
|
||||
.font(.caption2)
|
||||
|
||||
|
||||
// Only manage ham mode for the locally connected node
|
||||
if node?.num ?? 0 > 0 && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
if node?.num ?? 0 > 0 && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Toggle(isOn: $isLicensed) {
|
||||
Label("Licensed Operator", systemImage: "person.text.rectangle")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if isLicensed {
|
||||
|
||||
|
||||
Text("Onboarding for licensed operators requires firmware 2.0.20 or greater. Make sure to refer to your local regulations and contact the local amateur frequency coordinators with questions.")
|
||||
.font(.caption2)
|
||||
Text("What licensed operator mode does:\n* Sets the node name to your call sign \n* Broadcasts node info every 10 minutes \n* Overrides frequency, dutycycle and tx power \n* Disables encryption")
|
||||
.font(.caption2)
|
||||
|
||||
|
||||
HStack {
|
||||
Label("Frequency", systemImage: "waveform.path.ecg")
|
||||
Spacer()
|
||||
|
|
@ -141,11 +141,11 @@ struct UserConfig: View {
|
|||
titleVisibility: .visible
|
||||
) {
|
||||
Button("Save User Config to \(node?.user?.longName ?? "Unknown")?") {
|
||||
|
||||
|
||||
let connectedUser = getUser(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
|
||||
if node != nil && connectedNode != nil {
|
||||
|
||||
|
||||
if !isLicensed {
|
||||
var u = User()
|
||||
u.shortName = shortName
|
||||
|
|
@ -157,7 +157,7 @@ struct UserConfig: View {
|
|||
}
|
||||
} else {
|
||||
var ham = HamParameters()
|
||||
//ham.shortName = shortName
|
||||
// ham.shortName = shortName
|
||||
ham.callSign = longName
|
||||
ham.txPower = Int32(txPower)
|
||||
ham.frequency = overrideFrequency
|
||||
|
|
@ -204,11 +204,11 @@ struct UserConfig: View {
|
|||
if newIsLicensed != node?.user!.isLicensed { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: overrideFrequency) { newOverrideFrequency in
|
||||
//hasChanges = true
|
||||
.onChange(of: overrideFrequency) { _ in
|
||||
// hasChanges = true
|
||||
}
|
||||
.onChange(of: txPower) { newTxPower in
|
||||
//hasChanges = true
|
||||
.onChange(of: txPower) { _ in
|
||||
// hasChanges = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue