mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge branch 'main' into formatting_merge_conficts
This commit is contained in:
commit
68bdb82aa2
43 changed files with 888 additions and 895 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
48
.swiftlint.yml
Normal file
48
.swiftlint.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
line_length: 400
|
||||
|
||||
type_name:
|
||||
min_length: 1
|
||||
max_length:
|
||||
warning: 60
|
||||
error: 70
|
||||
excluded: iPhone # excluded via string
|
||||
allowed_symbols: ["_"] # these are allowed in type names
|
||||
identifier_name:
|
||||
min_length: 1
|
||||
max_length:
|
||||
warning: 60
|
||||
allowed_symbols: ["_"] # these are allowed in type names
|
||||
|
||||
# TODO: should review
|
||||
force_try:
|
||||
severity: warning # explicitly
|
||||
|
||||
# TODO: should review
|
||||
file_length:
|
||||
warning: 2500
|
||||
error: 3000
|
||||
|
||||
# TODO: should review
|
||||
cyclomatic_complexity:
|
||||
warning: 60
|
||||
error: 70
|
||||
ignores_case_statements: true
|
||||
|
||||
# TODO: should review
|
||||
function_body_length:
|
||||
warning: 200
|
||||
|
||||
# TODO: should review
|
||||
type_body_length:
|
||||
warning: 400
|
||||
|
||||
# TODO: should review
|
||||
disabled_rules: # rule identifiers to exclude from running
|
||||
- operator_whitespace
|
||||
- multiple_closures_with_trailing_closure
|
||||
- todo
|
||||
|
||||
# TODO: should review
|
||||
nesting:
|
||||
type_level:
|
||||
warning: 3
|
||||
|
|
@ -352,6 +352,7 @@
|
|||
DDC2E15026CE248E0042C5E4 /* Sources */,
|
||||
DDC2E15126CE248E0042C5E4 /* Frameworks */,
|
||||
DDC2E15226CE248E0042C5E4 /* Resources */,
|
||||
BB450974275599CE00509624 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
@ -472,6 +473,26 @@
|
|||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
BB450974275599CE00509624 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
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";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
DDC2E15026CE248E0042C5E4 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
|
|
|
|||
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6-1.png
vendored
Normal file
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6-1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 482 KiB |
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6-2.png
vendored
Normal file
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6-2.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 482 KiB |
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6.png
vendored
Normal file
BIN
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/655DCEC0-309D-430A-AF50-2453B6ADB1F6.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 482 KiB |
23
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/Contents.json
vendored
Normal file
23
MeshtasticClient/Assets.xcassets/HELTECV21.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "655DCEC0-309D-430A-AF50-2453B6ADB1F6.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "655DCEC0-309D-430A-AF50-2453B6ADB1F6-1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "655DCEC0-309D-430A-AF50-2453B6ADB1F6-2.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,24 +1,19 @@
|
|||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
extension Data
|
||||
{
|
||||
var hexDescription: String
|
||||
{
|
||||
extension Data {
|
||||
var hexDescription: String {
|
||||
return reduce("") {$0 + String(format: "%02x", $1)}
|
||||
}
|
||||
}
|
||||
|
||||
extension Date
|
||||
{
|
||||
static var currentTimeStamp: Int64
|
||||
{
|
||||
extension Date {
|
||||
static var currentTimeStamp: Int64 {
|
||||
return Int64(Date().timeIntervalSince1970 * 1000)
|
||||
}
|
||||
}
|
||||
|
||||
extension String
|
||||
{
|
||||
extension String {
|
||||
|
||||
/// Create `Data` from hexadecimal string representation
|
||||
///
|
||||
|
|
@ -26,8 +21,7 @@ extension String
|
|||
///
|
||||
/// - returns: Data represented by this hexadecimal string.
|
||||
|
||||
var hexadecimal: Data?
|
||||
{
|
||||
var hexadecimal: Data? {
|
||||
var data = Data(capacity: count / 2)
|
||||
|
||||
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
|
||||
|
|
@ -48,36 +42,36 @@ typealias NodeColor = Int
|
|||
|
||||
extension NodeColor {
|
||||
// a color to represent an individual meshtastic device
|
||||
var color: Color {
|
||||
switch self {
|
||||
case 0:
|
||||
return Color(.red)
|
||||
case 1:
|
||||
return Color(.blue)
|
||||
case 2:
|
||||
return Color(.yellow)
|
||||
case 3:
|
||||
return Color(.green)
|
||||
case 4:
|
||||
return Color(.purple)
|
||||
case 5:
|
||||
return Color(.systemPink)
|
||||
case 6:
|
||||
return Color(.systemTeal)
|
||||
case 7:
|
||||
return Color(.black)
|
||||
case 8:
|
||||
return Color(.gray)
|
||||
case 9:
|
||||
return Color(.brown)
|
||||
case 10:
|
||||
return Color(.magenta)
|
||||
case 11:
|
||||
return Color(.orange)
|
||||
case 12:
|
||||
return Color(.cyan)
|
||||
default:
|
||||
return Color(.blue)
|
||||
}
|
||||
}
|
||||
var color: Color {
|
||||
switch self {
|
||||
case 0:
|
||||
return Color(.red)
|
||||
case 1:
|
||||
return Color(.blue)
|
||||
case 2:
|
||||
return Color(.yellow)
|
||||
case 3:
|
||||
return Color(.green)
|
||||
case 4:
|
||||
return Color(.purple)
|
||||
case 5:
|
||||
return Color(.systemPink)
|
||||
case 6:
|
||||
return Color(.systemTeal)
|
||||
case 7:
|
||||
return Color(.black)
|
||||
case 8:
|
||||
return Color(.gray)
|
||||
case 9:
|
||||
return Color(.brown)
|
||||
case 10:
|
||||
return Color(.magenta)
|
||||
case 11:
|
||||
return Color(.orange)
|
||||
case 12:
|
||||
return Color(.cyan)
|
||||
default:
|
||||
return Color(.blue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,3 @@
|
|||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
class LocalNotificationManager {
|
||||
|
||||
var notifications = [Notification]()
|
||||
|
||||
|
||||
// Step 1 Request Permissions for notifications
|
||||
private func requestAuthorization()
|
||||
{
|
||||
private func requestAuthorization() {
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
|
||||
|
||||
if granted == true && error == nil {
|
||||
|
|
@ -16,9 +14,8 @@ class LocalNotificationManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func schedule()
|
||||
{
|
||||
|
||||
func schedule() {
|
||||
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
||||
switch settings.authorizationStatus {
|
||||
case .notDetermined:
|
||||
|
|
@ -30,12 +27,10 @@ class LocalNotificationManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function iterates over the Notification objects in the notifications array and schedules them for delivery in the future
|
||||
private func scheduleNotifications()
|
||||
{
|
||||
for notification in notifications
|
||||
{
|
||||
private func scheduleNotifications() {
|
||||
for notification in notifications {
|
||||
let content = UNMutableNotificationContent()
|
||||
content.subtitle = notification.subtitle
|
||||
content.title = notification.title
|
||||
|
|
@ -43,7 +38,6 @@ class LocalNotificationManager {
|
|||
content.sound = .default
|
||||
content.interruptionLevel = .timeSensitive
|
||||
|
||||
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
||||
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
|
||||
|
||||
|
|
@ -55,10 +49,9 @@ class LocalNotificationManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check and debug what local notifications have been scheduled
|
||||
func listScheduledNotifications()
|
||||
{
|
||||
func listScheduledNotifications() {
|
||||
UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
|
||||
|
||||
for notification in notifications {
|
||||
|
|
@ -66,8 +59,7 @@ class LocalNotificationManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct Notification {
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
import CoreLocation
|
||||
|
||||
class LocationHelper: NSObject, ObservableObject {
|
||||
|
||||
|
||||
static let shared = LocationHelper()
|
||||
|
||||
|
||||
// Mount Rainier
|
||||
static let DefaultLocation = CLLocationCoordinate2D(latitude: 46.879967, longitude: -121.726906)
|
||||
|
||||
|
||||
static var currentLocation: CLLocationCoordinate2D {
|
||||
|
||||
|
||||
guard let location = shared.locationManager.location else {
|
||||
return DefaultLocation
|
||||
}
|
||||
return location.coordinate
|
||||
}
|
||||
|
||||
|
||||
private let locationManager = CLLocationManager()
|
||||
|
||||
|
||||
private override init() {
|
||||
|
||||
|
||||
super.init()
|
||||
locationManager.delegate = self
|
||||
locationManager.desiredAccuracy = kCLLocationAccuracyBest
|
||||
|
|
@ -29,11 +29,11 @@ class LocationHelper: NSObject, ObservableObject {
|
|||
|
||||
extension LocationHelper: CLLocationManagerDelegate {
|
||||
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { }
|
||||
|
||||
|
||||
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
||||
print("Location manager failed with error: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
|
||||
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
|
||||
print("Location manager changed the status: \(status)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ class MeshData: ObservableObject {
|
|||
fatalError("Can't find documents directory.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static var fileURL: URL {
|
||||
return documentsFolder.appendingPathComponent("nodeinfo.data")
|
||||
}
|
||||
|
||||
|
||||
@Published var nodes: [NodeInfoModel] = []
|
||||
|
||||
func load() {
|
||||
|
|
@ -33,12 +33,11 @@ class MeshData: ObservableObject {
|
|||
do {
|
||||
// If the file is borked delete it so we stop crashing
|
||||
try FileManager.default.removeItem(at: Self.fileURL)
|
||||
}
|
||||
catch {
|
||||
|
||||
} catch {
|
||||
|
||||
fatalError("Can't delete saved node data.")
|
||||
}
|
||||
|
||||
|
||||
fatalError("Can't decode saved node data.")
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
class MessageData: ObservableObject {
|
||||
|
||||
|
||||
private static var documentsFolder: URL {
|
||||
do {
|
||||
return try FileManager.default.url(for: .documentDirectory,
|
||||
|
|
@ -12,13 +12,13 @@ class MessageData: ObservableObject {
|
|||
fatalError("Can't find documents directory.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static var fileURL: URL {
|
||||
return documentsFolder.appendingPathComponent("messages.data")
|
||||
}
|
||||
|
||||
|
||||
@Published var messages: [MessageModel] = []
|
||||
|
||||
|
||||
func load() {
|
||||
DispatchQueue.global(qos: .background).async { [weak self] in
|
||||
guard let data = try? Data(contentsOf: Self.fileURL) else {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@
|
|||
//
|
||||
import Foundation
|
||||
|
||||
struct MessageModel : Identifiable, Codable
|
||||
{
|
||||
struct MessageModel: Identifiable, Codable {
|
||||
let id: UUID
|
||||
var messageId: UInt32
|
||||
var messageTimestamp: UInt32
|
||||
|
|
@ -20,9 +19,8 @@ struct MessageModel : Identifiable, Codable
|
|||
var receivedACK: Bool
|
||||
var messagePayload: String
|
||||
var direction: String
|
||||
|
||||
init(id: UUID = UUID(), messageId: UInt32, messageTimeStamp: UInt32, fromUserId: UInt32, toUserId: UInt32, fromUserLongName: String, toUserLongName: String, fromUserShortName: String, toUserShortName: String, receivedACK: Bool, messagePayload: String, direction: String)
|
||||
{
|
||||
|
||||
init(id: UUID = UUID(), messageId: UInt32, messageTimeStamp: UInt32, fromUserId: UInt32, toUserId: UInt32, fromUserLongName: String, toUserLongName: String, fromUserShortName: String, toUserShortName: String, receivedACK: Bool, messagePayload: String, direction: String) {
|
||||
self.id = id
|
||||
self.messageId = messageId
|
||||
self.messageTimestamp = messageTimeStamp
|
||||
|
|
@ -43,7 +41,7 @@ extension MessageModel {
|
|||
|
||||
static var data: [MessageModel] {
|
||||
[
|
||||
//MessageModel(messageId: 3773493338, messageTimeStamp: 1632407404, fromUserId: 2930161432, toUserId: 4294967295, fromUserLongName: "TBEAM ARMY GREEN", toUserLongName: "Unknown 1", fromUserShortName: "GVH", toUserShortName: "U1", receivedACK: false, messagePayload: "yo", direction: "received")
|
||||
// MessageModel(messageId: 3773493338, messageTimeStamp: 1632407404, fromUserId: 2930161432, toUserId: 4294967295, fromUserLongName: "TBEAM ARMY GREEN", toUserLongName: "Unknown 1", fromUserShortName: "GVH", toUserShortName: "U1", receivedACK: false, messagePayload: "yo", direction: "received")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +60,7 @@ extension MessageModel {
|
|||
var receivedACK: Bool
|
||||
var messagePayload: String
|
||||
var direction: String
|
||||
|
||||
|
||||
}
|
||||
|
||||
var data: Data {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
struct MyInfoModel: Identifiable, Codable {
|
||||
|
||||
|
||||
// Uses the BLE Peripheral identifier as the ID
|
||||
// So myInfo can map between Peripherals and Nodes
|
||||
var id: UInt32
|
||||
|
|
@ -12,9 +12,9 @@ struct MyInfoModel: Identifiable, Codable {
|
|||
var firmwareVersion: String
|
||||
var messageTimeoutMsec: UInt32
|
||||
var minAppVersion: UInt32
|
||||
|
||||
|
||||
init(myNodeNum: UInt32, hasGps: Bool, numBands: UInt32, maxChannels: UInt32, firmwareVersion: String, messageTimeoutMsec: UInt32, minAppVersion: UInt32) {
|
||||
|
||||
|
||||
self.id = myNodeNum
|
||||
self.myNodeNum = myNodeNum
|
||||
self.hasGps = hasGps
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import SwiftUI
|
|||
import CoreLocation
|
||||
|
||||
struct NodeInfoModel: Identifiable, Codable {
|
||||
|
||||
|
||||
var id: UInt32
|
||||
var num: UInt32
|
||||
var myInfo: MyInfoModel?
|
||||
|
|
@ -15,7 +15,7 @@ struct NodeInfoModel: Identifiable, Codable {
|
|||
var longName: String
|
||||
var shortName: String
|
||||
var hwModel: String
|
||||
|
||||
|
||||
init(id: String, longName: String, shortName: String, hwModel: String) {
|
||||
self.id = id
|
||||
self.longName = longName
|
||||
|
|
@ -33,8 +33,7 @@ struct NodeInfoModel: Identifiable, Codable {
|
|||
return nil
|
||||
}
|
||||
return d / 1e7
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -46,25 +45,23 @@ struct NodeInfoModel: Identifiable, Codable {
|
|||
return nil
|
||||
}
|
||||
return d / 1e7
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
var coordinate: CLLocationCoordinate2D? {
|
||||
if latitude != nil && longitude != nil {
|
||||
let coord = CLLocationCoordinate2D(latitude: latitude!, longitude: longitude!)
|
||||
|
||||
|
||||
return coord
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
var altitude: Int32?
|
||||
var batteryLevel: Int32?
|
||||
var time: UInt32?
|
||||
|
||||
|
||||
init(latitudeI: Int32?, longitudeI: Int32?, altitude: Int32?, batteryLevel: Int32?, time: UInt32? ) {
|
||||
self.latitudeI = latitudeI
|
||||
self.longitudeI = longitudeI
|
||||
|
|
@ -73,11 +70,10 @@ struct NodeInfoModel: Identifiable, Codable {
|
|||
self.time = time
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var lastHeard: UInt32
|
||||
var snr: Float?
|
||||
|
||||
|
||||
init(num: UInt32, user: User, position: Position, lastHeard: UInt32, snr: Float?) {
|
||||
self.id = num
|
||||
self.num = num
|
||||
|
|
@ -106,7 +102,7 @@ extension NodeInfoModel {
|
|||
var postion: Position
|
||||
var lastHeard: UInt32
|
||||
var snr: Float?
|
||||
|
||||
|
||||
}
|
||||
|
||||
var data: Data {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ struct Peripheral: Identifiable {
|
|||
var rssi: Int
|
||||
var subscribed: Bool
|
||||
var peripheral: CBPeripheral
|
||||
|
||||
|
||||
var myInfo: MyInfoModel?
|
||||
|
||||
|
||||
init(id: String, name: String, rssi: Int, subscribed: Bool, peripheral: CBPeripheral, myInfo: MyInfoModel?) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
|||
|
|
@ -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 AdminMessage {
|
|||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var variant: AdminMessage.OneOf_Variant? = nil
|
||||
var variant: AdminMessage.OneOf_Variant?
|
||||
|
||||
///
|
||||
/// set the radio provisioning for this node
|
||||
|
|
@ -258,7 +258,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
32: .standard(proto: "confirm_set_channel"),
|
||||
33: .standard(proto: "confirm_set_radio"),
|
||||
34: .standard(proto: "exit_simulator"),
|
||||
35: .standard(proto: "reboot_seconds"),
|
||||
35: .standard(proto: "reboot_seconds")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,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
|
||||
}
|
||||
|
|
@ -230,7 +230,7 @@ extension ChannelSettings.ModemConfig: CaseIterable {
|
|||
.bw125Cr45Sf128,
|
||||
.bw500Cr45Sf128,
|
||||
.bw3125Cr48Sf512,
|
||||
.bw125Cr48Sf4096,
|
||||
.bw125Cr48Sf4096
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ struct Channel {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _settings: ChannelSettings? = nil
|
||||
fileprivate var _settings: ChannelSettings?
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
|
@ -329,7 +329,7 @@ extension Channel.Role: CaseIterable {
|
|||
static var allCases: [Channel.Role] = [
|
||||
.disabled,
|
||||
.primary,
|
||||
.secondary,
|
||||
.secondary
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
|
|||
5: .same(proto: "name"),
|
||||
10: .same(proto: "id"),
|
||||
16: .standard(proto: "uplink_enabled"),
|
||||
17: .standard(proto: "downlink_enabled"),
|
||||
17: .standard(proto: "downlink_enabled")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -434,7 +434,7 @@ extension ChannelSettings.ModemConfig: SwiftProtobuf._ProtoNameProviding {
|
|||
0: .same(proto: "Bw125Cr45Sf128"),
|
||||
1: .same(proto: "Bw500Cr45Sf128"),
|
||||
2: .same(proto: "Bw31_25Cr48Sf512"),
|
||||
3: .same(proto: "Bw125Cr48Sf4096"),
|
||||
3: .same(proto: "Bw125Cr48Sf4096")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +443,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 {
|
||||
|
|
@ -486,6 +486,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
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ struct LegacyRadioConfig {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _preferences: LegacyRadioConfig.LegacyPreferences? = nil
|
||||
fileprivate var _preferences: LegacyRadioConfig.LegacyPreferences?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -180,7 +180,7 @@ struct ChannelFile {
|
|||
extension LegacyRadioConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LegacyRadioConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "preferences"),
|
||||
1: .same(proto: "preferences")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -212,7 +212,7 @@ extension LegacyRadioConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
|
|||
extension LegacyRadioConfig.LegacyPreferences: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = LegacyRadioConfig.protoMessageName + ".LegacyPreferences"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
15: .same(proto: "region"),
|
||||
15: .same(proto: "region")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -252,17 +252,17 @@ 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 _legacyRadio: LegacyRadioConfig? = nil
|
||||
var _myNode: MyNodeInfo? = nil
|
||||
var _owner: User? = nil
|
||||
var _legacyRadio: LegacyRadioConfig?
|
||||
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
|
||||
|
||||
|
|
@ -372,7 +372,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "ChannelFile"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "channels"),
|
||||
1: .same(proto: "channels")
|
||||
]
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ extension EnvironmentalMeasurement: SwiftProtobuf.Message, SwiftProtobuf._Messag
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "temperature"),
|
||||
2: .standard(proto: "relative_humidity"),
|
||||
3: .standard(proto: "barometric_pressure"),
|
||||
3: .standard(proto: "barometric_pressure")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,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
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ extension HardwareModel: CaseIterable {
|
|||
.genieblocks,
|
||||
.nrf52Unknown,
|
||||
.portduino,
|
||||
.androidSim,
|
||||
.androidSim
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ extension Constants: CaseIterable {
|
|||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Constants] = [
|
||||
.unused,
|
||||
.dataPayloadLen,
|
||||
.dataPayloadLen
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +261,7 @@ enum CriticalErrorCode: SwiftProtobuf.Enum {
|
|||
case sx1262Failure // = 10
|
||||
|
||||
/// A (likely software but possibly hardware) failure was detected while trying to send packets. If this occurs on your board, please
|
||||
///post in the forum so that we can ask you to collect some information to allow fixing this bug
|
||||
/// post in the forum so that we can ask you to collect some information to allow fixing this bug
|
||||
case radioSpiBug // = 11
|
||||
case UNRECOGNIZED(Int)
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ extension CriticalErrorCode: CaseIterable {
|
|||
.transmitFailed,
|
||||
.brownout,
|
||||
.sx1262Failure,
|
||||
.radioSpiBug,
|
||||
.radioSpiBug
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -450,13 +450,13 @@ struct RouteDiscovery {
|
|||
}
|
||||
|
||||
///
|
||||
///A Routing control Data packet handled by the routing plugin
|
||||
/// A Routing control Data packet handled by the routing plugin
|
||||
struct Routing {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var variant: Routing.OneOf_Variant? = nil
|
||||
var variant: Routing.OneOf_Variant?
|
||||
|
||||
///
|
||||
/// A route request going from the requester
|
||||
|
|
@ -635,7 +635,7 @@ extension Routing.Error: CaseIterable {
|
|||
.tooLarge,
|
||||
.noResponse,
|
||||
.badRequest,
|
||||
.notAuthorized,
|
||||
.notAuthorized
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -719,7 +719,7 @@ struct MeshPacket {
|
|||
/// This 'trick' is only used while the payloadVariant is an 'encrypted'.
|
||||
var channel: UInt32 = 0
|
||||
|
||||
var payloadVariant: MeshPacket.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: MeshPacket.OneOf_PayloadVariant?
|
||||
|
||||
var decoded: DataMessage {
|
||||
get {
|
||||
|
|
@ -915,7 +915,7 @@ extension MeshPacket.Priority: CaseIterable {
|
|||
.default,
|
||||
.reliable,
|
||||
.ack,
|
||||
.max,
|
||||
.max
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -988,8 +988,8 @@ struct NodeInfo {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _user: User? = nil
|
||||
fileprivate var _position: Position? = nil
|
||||
fileprivate var _user: User?
|
||||
fileprivate var _position: Position?
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -1169,7 +1169,7 @@ extension LogRecord.Level: CaseIterable {
|
|||
.warning,
|
||||
.info,
|
||||
.debug,
|
||||
.trace,
|
||||
.trace
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1341,7 +1341,7 @@ struct ToRadio {
|
|||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var payloadVariant: ToRadio.OneOf_PayloadVariant? = nil
|
||||
var payloadVariant: ToRadio.OneOf_PayloadVariant?
|
||||
|
||||
///
|
||||
/// send this packet on the mesh
|
||||
|
|
@ -1495,14 +1495,14 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
35: .same(proto: "GENIEBLOCKS"),
|
||||
36: .same(proto: "NRF52_UNKNOWN"),
|
||||
37: .same(proto: "PORTDUINO"),
|
||||
38: .same(proto: "ANDROID_SIM"),
|
||||
38: .same(proto: "ANDROID_SIM")
|
||||
]
|
||||
}
|
||||
|
||||
extension Constants: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "Unused"),
|
||||
237: .same(proto: "DATA_PAYLOAD_LEN"),
|
||||
237: .same(proto: "DATA_PAYLOAD_LEN")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1519,7 +1519,7 @@ extension CriticalErrorCode: SwiftProtobuf._ProtoNameProviding {
|
|||
8: .same(proto: "TransmitFailed"),
|
||||
9: .same(proto: "Brownout"),
|
||||
10: .same(proto: "SX1262Failure"),
|
||||
11: .same(proto: "RadioSpiBug"),
|
||||
11: .same(proto: "RadioSpiBug")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1530,7 +1530,7 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
2: .standard(proto: "longitude_i"),
|
||||
3: .same(proto: "altitude"),
|
||||
4: .standard(proto: "battery_level"),
|
||||
9: .same(proto: "time"),
|
||||
9: .same(proto: "time")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1587,7 +1587,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
|
|||
3: .standard(proto: "short_name"),
|
||||
4: .same(proto: "macaddr"),
|
||||
6: .standard(proto: "hw_model"),
|
||||
7: .standard(proto: "is_licensed"),
|
||||
7: .standard(proto: "is_licensed")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1644,7 +1644,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
|
|||
extension RouteDiscovery: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "RouteDiscovery"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
2: .same(proto: "route"),
|
||||
2: .same(proto: "route")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1678,7 +1678,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 {
|
||||
|
|
@ -1767,7 +1767,7 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding {
|
|||
7: .same(proto: "TOO_LARGE"),
|
||||
8: .same(proto: "NO_RESPONSE"),
|
||||
32: .same(proto: "BAD_REQUEST"),
|
||||
33: .same(proto: "NOT_AUTHORIZED"),
|
||||
33: .same(proto: "NOT_AUTHORIZED")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1779,7 +1779,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
|
|||
3: .standard(proto: "want_response"),
|
||||
4: .same(proto: "dest"),
|
||||
5: .same(proto: "source"),
|
||||
6: .standard(proto: "request_id"),
|
||||
6: .standard(proto: "request_id")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1847,7 +1847,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
10: .standard(proto: "hop_limit"),
|
||||
11: .standard(proto: "want_ack"),
|
||||
12: .same(proto: "priority"),
|
||||
13: .standard(proto: "rx_rssi"),
|
||||
13: .standard(proto: "rx_rssi")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1965,7 +1965,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")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -1976,7 +1976,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
2: .same(proto: "user"),
|
||||
3: .same(proto: "position"),
|
||||
7: .same(proto: "snr"),
|
||||
4: .standard(proto: "last_heard"),
|
||||
4: .standard(proto: "last_heard")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2040,7 +2040,7 @@ extension MyNodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
|
|||
9: .standard(proto: "error_count"),
|
||||
10: .standard(proto: "reboot_count"),
|
||||
13: .standard(proto: "message_timeout_msec"),
|
||||
14: .standard(proto: "min_app_version"),
|
||||
14: .standard(proto: "min_app_version")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2135,7 +2135,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 {
|
||||
|
|
@ -2187,7 +2187,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")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -2200,7 +2200,7 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
4: .standard(proto: "node_info"),
|
||||
7: .standard(proto: "log_record"),
|
||||
8: .standard(proto: "config_complete_id"),
|
||||
9: .same(proto: "rebooted"),
|
||||
9: .same(proto: "rebooted")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -2368,7 +2368,7 @@ extension ToRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
2: .same(proto: "packet"),
|
||||
3: .standard(proto: "peer_info"),
|
||||
100: .standard(proto: "want_config_id"),
|
||||
104: .same(proto: "disconnect"),
|
||||
104: .same(proto: "disconnect")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -2461,7 +2461,7 @@ extension ToRadio.PeerInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImpleme
|
|||
static let protoMessageName: String = ToRadio.protoMessageName + ".PeerInfo"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "app_version"),
|
||||
2: .standard(proto: "mqtt_gateway"),
|
||||
2: .standard(proto: "mqtt_gateway")
|
||||
]
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -68,11 +68,11 @@ extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
|
|||
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")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _packet: MeshPacket? = nil
|
||||
var _packet: MeshPacket?
|
||||
var _channelID: String = String()
|
||||
var _gatewayID: String = String()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ extension PortNum: CaseIterable {
|
|||
.environmentalMeasurementApp,
|
||||
.privateApp,
|
||||
.atakForwarder,
|
||||
.max,
|
||||
.max
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +222,6 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding {
|
|||
67: .same(proto: "ENVIRONMENTAL_MEASUREMENT_APP"),
|
||||
256: .same(proto: "PRIVATE_APP"),
|
||||
257: .same(proto: "ATAK_FORWARDER"),
|
||||
511: .same(proto: "MAX"),
|
||||
511: .same(proto: "MAX")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,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
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ extension RegionCode: CaseIterable {
|
|||
.anz,
|
||||
.kr,
|
||||
.tw,
|
||||
.ru,
|
||||
.ru
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ extension ChargeCurrent: CaseIterable {
|
|||
.ma1080,
|
||||
.ma1160,
|
||||
.ma1240,
|
||||
.ma1320,
|
||||
.ma1320
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -292,7 +292,7 @@ extension GpsOperation: CaseIterable {
|
|||
.gpsOpStationary,
|
||||
.gpsOpMobile,
|
||||
.gpsOpTimeOnly,
|
||||
.gpsOpDisabled,
|
||||
.gpsOpDisabled
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -375,7 +375,7 @@ extension GpsCoordinateFormat: CaseIterable {
|
|||
.gpsFormatUtm,
|
||||
.gpsFormatMgrs,
|
||||
.gpsFormatOlc,
|
||||
.gpsFormatOsgr,
|
||||
.gpsFormatOsgr
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ extension LocationSharing: CaseIterable {
|
|||
static var allCases: [LocationSharing] = [
|
||||
.locUnset,
|
||||
.locEnabled,
|
||||
.locDisabled,
|
||||
.locDisabled
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -789,7 +789,7 @@ struct RadioConfig {
|
|||
}
|
||||
|
||||
///
|
||||
///Preferences for the RangeTestPlugin
|
||||
/// Preferences for the RangeTestPlugin
|
||||
/// FIXME - Move this out of UserPreferences and into a section for plugin configuration.
|
||||
var rangeTestPluginEnabled: Bool {
|
||||
get {return _storage._rangeTestPluginEnabled}
|
||||
|
|
@ -808,7 +808,7 @@ struct RadioConfig {
|
|||
|
||||
///
|
||||
/// Preferences for the StoreForwardPlugin
|
||||
///FIXME - Move this out of UserPreferences and into a section for plugin configuration. (was 136)
|
||||
/// FIXME - Move this out of UserPreferences and into a section for plugin configuration. (was 136)
|
||||
var storeForwardPluginEnabled: Bool {
|
||||
get {return _storage._storeForwardPluginEnabled}
|
||||
set {_uniqueStorage()._storeForwardPluginEnabled = newValue}
|
||||
|
|
@ -917,7 +917,7 @@ struct RadioConfig {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _preferences: RadioConfig.UserPreferences? = nil
|
||||
fileprivate var _preferences: RadioConfig.UserPreferences?
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
|
@ -925,7 +925,7 @@ struct RadioConfig {
|
|||
extension RadioConfig.UserPreferences.EnvironmentalMeasurementSensorType: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [RadioConfig.UserPreferences.EnvironmentalMeasurementSensorType] = [
|
||||
.dht11,
|
||||
.dht11
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -944,7 +944,7 @@ extension RegionCode: SwiftProtobuf._ProtoNameProviding {
|
|||
6: .same(proto: "ANZ"),
|
||||
7: .same(proto: "KR"),
|
||||
8: .same(proto: "TW"),
|
||||
9: .same(proto: "RU"),
|
||||
9: .same(proto: "RU")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -966,7 +966,7 @@ extension ChargeCurrent: SwiftProtobuf._ProtoNameProviding {
|
|||
13: .same(proto: "MA1080"),
|
||||
14: .same(proto: "MA1160"),
|
||||
15: .same(proto: "MA1240"),
|
||||
16: .same(proto: "MA1320"),
|
||||
16: .same(proto: "MA1320")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -976,7 +976,7 @@ extension GpsOperation: SwiftProtobuf._ProtoNameProviding {
|
|||
1: .same(proto: "GpsOpStationary"),
|
||||
2: .same(proto: "GpsOpMobile"),
|
||||
3: .same(proto: "GpsOpTimeOnly"),
|
||||
4: .same(proto: "GpsOpDisabled"),
|
||||
4: .same(proto: "GpsOpDisabled")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -987,7 +987,7 @@ extension GpsCoordinateFormat: SwiftProtobuf._ProtoNameProviding {
|
|||
2: .same(proto: "GpsFormatUTM"),
|
||||
3: .same(proto: "GpsFormatMGRS"),
|
||||
4: .same(proto: "GpsFormatOLC"),
|
||||
5: .same(proto: "GpsFormatOSGR"),
|
||||
5: .same(proto: "GpsFormatOSGR")
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -995,14 +995,14 @@ extension LocationSharing: SwiftProtobuf._ProtoNameProviding {
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "LocUnset"),
|
||||
1: .same(proto: "LocEnabled"),
|
||||
2: .same(proto: "LocDisabled"),
|
||||
2: .same(proto: "LocDisabled")
|
||||
]
|
||||
}
|
||||
|
||||
extension RadioConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "RadioConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "preferences"),
|
||||
1: .same(proto: "preferences")
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1088,7 +1088,7 @@ extension RadioConfig.UserPreferences: SwiftProtobuf.Message, SwiftProtobuf._Mes
|
|||
144: .standard(proto: "environmental_measurement_plugin_recovery_interval"),
|
||||
145: .standard(proto: "environmental_measurement_plugin_display_farenheit"),
|
||||
146: .standard(proto: "environmental_measurement_plugin_sensor_type"),
|
||||
147: .standard(proto: "environmental_measurement_plugin_sensor_pin"),
|
||||
147: .standard(proto: "environmental_measurement_plugin_sensor_pin")
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -1529,6 +1529,6 @@ extension RadioConfig.UserPreferences: SwiftProtobuf.Message, SwiftProtobuf._Mes
|
|||
|
||||
extension RadioConfig.UserPreferences.EnvironmentalMeasurementSensorType: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "DHT11"),
|
||||
0: .same(proto: "DHT11")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ extension HardwareMessage.TypeEnum: CaseIterable {
|
|||
.watchGpios,
|
||||
.gpiosChanged,
|
||||
.readGpios,
|
||||
.readGpiosReply,
|
||||
.readGpiosReply
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ extension HardwareMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "typ"),
|
||||
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 {
|
||||
|
|
@ -185,6 +185,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")
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,47 +14,46 @@ import CoreLocation
|
|||
import CoreBluetooth
|
||||
|
||||
struct Connect: View {
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
@State var isPreferredRadio: Bool = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
NavigationView {
|
||||
|
||||
|
||||
VStack {
|
||||
if bleManager.isSwitchedOn {
|
||||
|
||||
|
||||
List {
|
||||
if bleManager.lastConnectionError.count > 0 {
|
||||
|
||||
|
||||
Section(header: Text("Connection Error").font(.title)) {
|
||||
|
||||
|
||||
Text(bleManager.lastConnectionError).font(.title3).foregroundColor(.red)
|
||||
}
|
||||
.textCase(nil)
|
||||
}
|
||||
|
||||
|
||||
Section(header: Text("Connected Radio").font(.title)) {
|
||||
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
|
||||
HStack {
|
||||
|
||||
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.green)
|
||||
.padding(.trailing)
|
||||
|
||||
VStack (alignment: .leading) {
|
||||
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
if bleManager.connectedNode != nil {
|
||||
|
||||
|
||||
Text(bleManager.connectedNode.user.longName).font(.title2)
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
|
||||
Text(String(bleManager.connectedPeripheral.peripheral.name ?? "Unknown")).font(.title2)
|
||||
}
|
||||
if bleManager.connectedNode != nil {
|
||||
|
|
@ -69,9 +68,9 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
Spacer()
|
||||
|
||||
VStack (alignment: .center) {
|
||||
|
||||
|
||||
VStack(alignment: .center) {
|
||||
|
||||
Text("Preferred").font(.caption2)
|
||||
Text("Radio").font(.caption2)
|
||||
Toggle("Preferred Radio", isOn: $isPreferredRadio)
|
||||
|
|
@ -79,7 +78,7 @@ struct Connect: View {
|
|||
.labelsHidden()
|
||||
.onChange(of: isPreferredRadio) { value in
|
||||
if value {
|
||||
|
||||
|
||||
if bleManager.connectedNode != nil {
|
||||
let deviceName = "\(bleManager.connectedNode.user.longName) / \(bleManager.connectedPeripheral.peripheral.name ?? "")"
|
||||
|
||||
|
|
@ -87,13 +86,13 @@ struct Connect: View {
|
|||
} else {
|
||||
userSettings.preferredPeripheralName = bleManager.connectedPeripheral.peripheral.name ?? "Unknown Device"
|
||||
}
|
||||
|
||||
|
||||
userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.identifier.uuidString == userSettings.preferredPeripheralId {
|
||||
|
||||
|
||||
userSettings.preferredPeripheralId = ""
|
||||
userSettings.preferredPeripheralName = ""
|
||||
}
|
||||
|
|
@ -102,10 +101,9 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
.swipeActions {
|
||||
|
||||
|
||||
Button(role: .destructive) {
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected
|
||||
{
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral()
|
||||
isPreferredRadio = false
|
||||
}
|
||||
|
|
@ -114,9 +112,8 @@ struct Connect: View {
|
|||
}
|
||||
}
|
||||
.padding([.top, .bottom])
|
||||
}
|
||||
else {
|
||||
HStack{
|
||||
} else {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.red)
|
||||
|
|
@ -125,10 +122,10 @@ struct Connect: View {
|
|||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.textCase(nil)
|
||||
|
||||
|
||||
if bleManager.peripherals.count > 0 {
|
||||
Section(header: Text("Available Radios").font(.title)) {
|
||||
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name < $1.name })) { peripheral in
|
||||
|
|
@ -138,18 +135,16 @@ struct Connect: View {
|
|||
.padding(.trailing)
|
||||
Button(action: {
|
||||
self.bleManager.stopScanning()
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected
|
||||
{
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
|
||||
self.bleManager.disconnectPeripheral()
|
||||
}
|
||||
self.bleManager.connectTo(peripheral: peripheral.peripheral)
|
||||
if userSettings.preferredPeripheralId == peripheral.peripheral.identifier.uuidString {
|
||||
|
||||
|
||||
isPreferredRadio = true
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
|
||||
isPreferredRadio = false
|
||||
}
|
||||
}) {
|
||||
|
|
@ -157,13 +152,13 @@ struct Connect: View {
|
|||
}
|
||||
Spacer()
|
||||
Text(String(peripheral.rssi) + " dB").font(.title3)
|
||||
}.padding([.bottom,.top])
|
||||
}.padding([.bottom, .top])
|
||||
}
|
||||
}.textCase(nil)
|
||||
}
|
||||
}
|
||||
|
||||
HStack (alignment: .center) {
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
self.bleManager.startScanning()
|
||||
|
|
@ -193,9 +188,8 @@ struct Connect: View {
|
|||
Spacer()
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
Text("Bluetooth: OFF")
|
||||
.foregroundColor(.red)
|
||||
.font(.title)
|
||||
|
|
@ -203,7 +197,7 @@ struct Connect: View {
|
|||
}
|
||||
.navigationTitle("Bluetooth Radios")
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
|
||||
ZStack {
|
||||
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
|
||||
|
|
@ -215,8 +209,7 @@ struct Connect: View {
|
|||
|
||||
if bleManager.connectedPeripheral != nil && userSettings.preferredPeripheralId == bleManager.connectedPeripheral.peripheral.identifier.uuidString {
|
||||
isPreferredRadio = true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
isPreferredRadio = false
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
TabView(selection: $selection) {
|
||||
Channels()
|
||||
.tabItem {
|
||||
|
|
|
|||
|
|
@ -4,46 +4,41 @@ struct BatteryIcon: View {
|
|||
var batteryLevel: Int32?
|
||||
var font: Font
|
||||
var color: Color
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
if batteryLevel == 100 {
|
||||
|
||||
|
||||
Image(systemName: "battery.100.bolt")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else if batteryLevel! < 100 && batteryLevel! > 74 {
|
||||
|
||||
} else if batteryLevel! < 100 && batteryLevel! > 74 {
|
||||
|
||||
Image(systemName: "battery.75")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else if batteryLevel! < 75 && batteryLevel! > 49 {
|
||||
|
||||
} else if batteryLevel! < 75 && batteryLevel! > 49 {
|
||||
|
||||
Image(systemName: "battery.50")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else if batteryLevel! < 50 && batteryLevel! > 14 {
|
||||
|
||||
} else if batteryLevel! < 50 && batteryLevel! > 14 {
|
||||
|
||||
Image(systemName: "battery.25")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else if batteryLevel! == 0 {
|
||||
|
||||
} else if batteryLevel! == 0 {
|
||||
|
||||
Image(systemName: "powerplug")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
|
||||
Image(systemName: "battery.0")
|
||||
.font(font)
|
||||
.foregroundColor(color)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ struct ConnectedDevice: View {
|
|||
var name: String?
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
if bluetoothOn {
|
||||
|
|
@ -21,18 +21,16 @@ struct ConnectedDevice: View {
|
|||
.foregroundColor(.green)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text(name!).font(.subheadline).foregroundColor(.gray)
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.imageScale(.medium)
|
||||
.foregroundColor(.red)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("Disconnected").font(.subheadline).foregroundColor(.gray)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Bluetooth Off").font(.subheadline).foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,9 +41,9 @@ struct ConnectedDevice_Previews: PreviewProvider {
|
|||
static var previews: some View {
|
||||
ConnectedDevice(bluetoothOn: true, deviceConnected: false, name: "Yellow Beam")
|
||||
.previewLayout(.fixed(width: 80, height: 70))
|
||||
|
||||
ConnectedDevice(bluetoothOn: true, deviceConnected: false, name: "Yellow Beam")
|
||||
|
||||
ConnectedDevice(bluetoothOn: true, deviceConnected: false, name: "Yellow Beam")
|
||||
.previewLayout(.fixed(width: 80, height: 70))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,40 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessageBubble: View {
|
||||
|
||||
|
||||
@State var showAlert = false
|
||||
var contentMessage: String
|
||||
var isCurrentUser: Bool
|
||||
var time: Int32
|
||||
var shortName: String
|
||||
var id: UInt32
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
HStack (alignment: .top) {
|
||||
|
||||
|
||||
HStack(alignment: .top) {
|
||||
|
||||
CircleText(text: shortName, color: isCurrentUser ? Color.blue : Color(.darkGray)).padding(.all, 5)
|
||||
.gesture(LongPressGesture(minimumDuration: 2)
|
||||
.onEnded {_ in
|
||||
print("I want to delete message: \(id)")
|
||||
self.showAlert = true
|
||||
})
|
||||
|
||||
|
||||
VStack (alignment: .leading) {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(contentMessage)
|
||||
.textSelection(.enabled)
|
||||
.padding(10)
|
||||
.foregroundColor(.white)
|
||||
.background(isCurrentUser ? Color.blue : Color(.darkGray))
|
||||
.cornerRadius(10)
|
||||
HStack (spacing: 4) {
|
||||
|
||||
HStack(spacing: 4) {
|
||||
|
||||
let messageDate = Date(timeIntervalSince1970: TimeInterval(time))
|
||||
|
||||
if time != 0 {
|
||||
Text(messageDate, style: .date).font(.caption2).foregroundColor(.gray)
|
||||
Text(messageDate, style: .time).font(.caption2).foregroundColor(.gray)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Unknown").font(.caption2).foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
|
|
@ -46,11 +44,11 @@ struct MessageBubble: View {
|
|||
}
|
||||
.alert(isPresented: $showAlert) {
|
||||
Alert(title: Text("Are you sure you want to delete this message?"), message: Text("This action is permanent."),
|
||||
primaryButton: .destructive (Text("OK")) {
|
||||
primaryButton: .destructive(Text("OK")) {
|
||||
print("OK button tapped")
|
||||
//let messageIndex = meshData.nodes.firstIndex(where: { $0.id == node.id })
|
||||
//meshData.nodes.remove(at: nodeIndex!)
|
||||
//meshData.save()
|
||||
// let messageIndex = meshData.nodes.firstIndex(where: { $0.id == node.id })
|
||||
// meshData.nodes.remove(at: nodeIndex!)
|
||||
// meshData.save()
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
|
|
@ -66,5 +64,3 @@ struct MessageBubble_Previews: PreviewProvider {
|
|||
.previewLayout(.fixed(width: 300, height: 100))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,31 +3,30 @@ import SwiftUI
|
|||
import CoreBluetooth
|
||||
|
||||
struct Channels: View {
|
||||
|
||||
|
||||
@State private var isShowingDetailView = true
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
|
||||
NavigationView {
|
||||
|
||||
GeometryReader { bounds in
|
||||
|
||||
|
||||
GeometryReader { _ in
|
||||
|
||||
NavigationLink(destination: Messages(), isActive: $isShowingDetailView) {
|
||||
|
||||
List{
|
||||
|
||||
|
||||
List {
|
||||
|
||||
HStack {
|
||||
|
||||
|
||||
Image(systemName: "dial.max.fill")
|
||||
.font(.system(size: 62))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.padding(.trailing)
|
||||
.foregroundColor(.accentColor)
|
||||
|
||||
|
||||
Text("Primary")
|
||||
.font(.largeTitle)
|
||||
|
||||
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +38,7 @@ struct Channels: View {
|
|||
}
|
||||
|
||||
struct MessageList_Previews: PreviewProvider {
|
||||
|
||||
|
||||
static let meshData = MeshData()
|
||||
|
||||
static var previews: some View {
|
||||
|
|
|
|||
|
|
@ -4,78 +4,76 @@ import Foundation
|
|||
import CoreLocation
|
||||
|
||||
struct Messages: View {
|
||||
|
||||
|
||||
enum Field: Hashable {
|
||||
case messageText
|
||||
}
|
||||
|
||||
|
||||
// Keyboard State
|
||||
@State var typingMessage: String = ""
|
||||
@State private var totalBytes = 0
|
||||
private var maxbytes = 228
|
||||
@State private var lastTypingMessage = ""
|
||||
@FocusState private var focusedField: Field?
|
||||
|
||||
|
||||
@Namespace var topId
|
||||
@Namespace var bottomId
|
||||
|
||||
|
||||
@State var showDeleteMessageAlert = false
|
||||
@State private var deleteMessageId : UInt32 = 0
|
||||
|
||||
@State private var deleteMessageId: UInt32 = 0
|
||||
|
||||
// Message Data and Bluetooth
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
public var broadcastNodeId: UInt32 = 4294967295
|
||||
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
|
||||
@State var messageCount: Int = 0;
|
||||
|
||||
@State var messageCount: Int = 0
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
Text("\(messageCount) Messages").font(.caption)
|
||||
GeometryReader { bounds in
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
|
||||
ScrollViewReader { scrollView in
|
||||
|
||||
|
||||
if self.bleManager.messageData.messages.count > 0 {
|
||||
|
||||
|
||||
ScrollView {
|
||||
|
||||
|
||||
Text("Hidden Top Anchor").hidden().frame(height: 0).id(topId)
|
||||
|
||||
|
||||
ForEach(bleManager.messageData.messages.sorted(by: { $0.messageTimestamp < $1.messageTimestamp })) { message in
|
||||
|
||||
HStack (alignment: .top) {
|
||||
|
||||
HStack(alignment: .top) {
|
||||
let currentUser: Bool = (bleManager.connectedNode != nil) && ((bleManager.connectedNode.id) == message.fromUserId)
|
||||
|
||||
|
||||
CircleText(text: message.fromUserShortName, color: currentUser ? .accentColor : Color(.darkGray)).padding(.all, 5)
|
||||
.gesture(LongPressGesture(minimumDuration: 2)
|
||||
.onEnded {_ in
|
||||
print("I want to delete message: \(message.messageId)")
|
||||
self.showDeleteMessageAlert = true
|
||||
self.deleteMessageId = message.messageId
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
VStack (alignment: .leading) {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(message.messagePayload)
|
||||
.textSelection(.enabled)
|
||||
.padding(10)
|
||||
.foregroundColor(.white)
|
||||
.background(currentUser ? Color.blue : Color(.darkGray))
|
||||
.cornerRadius(10)
|
||||
HStack (spacing: 4) {
|
||||
|
||||
HStack(spacing: 4) {
|
||||
|
||||
let time = Int32(message.messageTimestamp)
|
||||
let messageDate = Date(timeIntervalSince1970: TimeInterval(time))
|
||||
|
||||
if time != 0 {
|
||||
Text(messageDate, style: .date).font(.caption2).foregroundColor(.gray)
|
||||
Text(messageDate, style: .time).font(.caption2).foregroundColor(.gray)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Unknown").font(.caption2).foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
|
|
@ -85,10 +83,10 @@ struct Messages: View {
|
|||
}
|
||||
.alert(isPresented: $showDeleteMessageAlert) {
|
||||
Alert(title: Text("Are you sure you want to delete this message?"), message: Text("This action is permanent."),
|
||||
primaryButton: .destructive (Text("Delete")) {
|
||||
primaryButton: .destructive(Text("Delete")) {
|
||||
print("OK button tapped")
|
||||
if deleteMessageId > 0 {
|
||||
|
||||
|
||||
let messageIndex = bleManager.messageData.messages.firstIndex(where: { $0.messageId == deleteMessageId })
|
||||
bleManager.messageData.messages.remove(at: messageIndex!)
|
||||
bleManager.messageData.save()
|
||||
|
|
@ -101,13 +99,13 @@ struct Messages: View {
|
|||
)
|
||||
}
|
||||
}
|
||||
.onAppear(perform: { scrollView.scrollTo(bottomId) } )
|
||||
.onAppear(perform: { scrollView.scrollTo(bottomId) })
|
||||
Text("Hidden Bottom Anchor").hidden().frame(height: 0).id(bottomId)
|
||||
}
|
||||
.onReceive(timer) { input in
|
||||
|
||||
.onReceive(timer) { _ in
|
||||
|
||||
if messageCount < bleManager.messageData.messages.count {
|
||||
|
||||
|
||||
bleManager.messageData.load()
|
||||
scrollView.scrollTo(bottomId)
|
||||
messageCount = bleManager.messageData.messages.count
|
||||
|
|
@ -116,9 +114,9 @@ struct Messages: View {
|
|||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
HStack (alignment: .top) {
|
||||
|
||||
|
||||
HStack(alignment: .top) {
|
||||
|
||||
ZStack {
|
||||
|
||||
let kbType = UIKeyboardType(rawValue: UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0)
|
||||
|
|
@ -130,24 +128,22 @@ struct Messages: View {
|
|||
if totalBytes <= maxbytes {
|
||||
// Allow the user to type
|
||||
lastTypingMessage = typingMessage
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Set the message back and remove the bytes over the count
|
||||
self.typingMessage = lastTypingMessage
|
||||
}
|
||||
})
|
||||
.keyboardType(kbType!)
|
||||
.toolbar
|
||||
{
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
|
||||
|
||||
Button("Dismiss Keyboard") {
|
||||
focusedField = nil
|
||||
}
|
||||
.font(.subheadline)
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
|
||||
ProgressView("Bytes: \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
|
|
@ -159,32 +155,30 @@ struct Messages: View {
|
|||
.focused($focusedField, equals: .messageText)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(minHeight: bounds.size.height / 4, maxHeight: bounds.size.height / 4)
|
||||
|
||||
|
||||
|
||||
Text(typingMessage).opacity(0).padding(.all, 0)
|
||||
|
||||
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
.padding(.bottom, 15)
|
||||
|
||||
|
||||
Button(action: {
|
||||
if bleManager.sendMessage(message: typingMessage) {
|
||||
typingMessage = ""
|
||||
}
|
||||
else {
|
||||
|
||||
let _ = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (timer) in
|
||||
|
||||
} else {
|
||||
|
||||
_ = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (_) in
|
||||
|
||||
if bleManager.sendMessage(message: typingMessage) {
|
||||
typingMessage = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} ) {
|
||||
|
||||
}) {
|
||||
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.blue)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.padding(.all, 15)
|
||||
}
|
||||
|
|
@ -192,13 +186,13 @@ struct Messages: View {
|
|||
.navigationTitle("Channel - Primary")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
|
||||
ZStack {
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
|
||||
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
|
||||
messageCount = bleManager.messageData.messages.count
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,27 +8,27 @@ import MapKit
|
|||
import CoreLocation
|
||||
|
||||
struct NodeDetail: View {
|
||||
|
||||
@EnvironmentObject var bleManager :BLEManager
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
var node: NodeInfoModel
|
||||
|
||||
|
||||
struct MapLocation: Identifiable {
|
||||
let id = UUID()
|
||||
let name: String
|
||||
let coordinate: CLLocationCoordinate2D
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
GeometryReader { bounds in
|
||||
|
||||
|
||||
VStack {
|
||||
|
||||
if(node.position.coordinate != nil) {
|
||||
|
||||
|
||||
if node.position.coordinate != nil {
|
||||
|
||||
let nodeCoordinatePosition = CLLocationCoordinate2D(latitude: node.position.latitude!, longitude: node.position.longitude!)
|
||||
|
||||
|
||||
let regionBinding = Binding<MKCoordinateRegion>(
|
||||
get: {
|
||||
MKCoordinateRegion(center: nodeCoordinatePosition, span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
|
||||
|
|
@ -36,7 +36,7 @@ struct NodeDetail: View {
|
|||
set: { _ in }
|
||||
)
|
||||
let annotations = [MapLocation(name: node.user.shortName, coordinate: node.position.coordinate!)]
|
||||
|
||||
|
||||
Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none, annotationItems: annotations) { location in
|
||||
MapAnnotation(
|
||||
coordinate: location.coordinate,
|
||||
|
|
@ -44,29 +44,27 @@ struct NodeDetail: View {
|
|||
CircleText(text: node.user.shortName, color: .accentColor)
|
||||
}
|
||||
)
|
||||
}.frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 2)
|
||||
}
|
||||
else
|
||||
{
|
||||
}.frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 2)
|
||||
} else {
|
||||
Image(node.user.hwModel)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: bounds.size.width, height: bounds.size.height / 2)
|
||||
}
|
||||
ScrollView {
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
|
||||
VStack(alignment: .center) {
|
||||
Text("AKA").font(.title2).fixedSize()
|
||||
CircleText(text: node.user.shortName, color: .accentColor)
|
||||
.offset(y:10)
|
||||
.offset(y: 10)
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
Divider()
|
||||
if node.snr != nil && node.snr! > 0 {
|
||||
VStack(alignment: .center) {
|
||||
|
||||
|
||||
Image(systemName: "waveform.path")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
|
|
@ -86,38 +84,37 @@ struct NodeDetail: View {
|
|||
.font(.title2)
|
||||
.foregroundColor(.gray)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Powered").font(.title2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}.padding(4)
|
||||
Divider()
|
||||
HStack {
|
||||
|
||||
|
||||
Image(node.user.hwModel)
|
||||
.resizable()
|
||||
.frame(width:60, height: 60)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(5)
|
||||
|
||||
|
||||
Text("Model: " + String(node.user.hwModel))
|
||||
.font(.title3)
|
||||
}
|
||||
.padding()
|
||||
Divider()
|
||||
|
||||
|
||||
if node.lastHeard > 0 {
|
||||
|
||||
HStack{
|
||||
|
||||
|
||||
HStack {
|
||||
|
||||
Image(systemName: "clock").font(.title2).foregroundColor(.accentColor)
|
||||
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
|
||||
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.title3)
|
||||
}.padding()
|
||||
Divider()
|
||||
}
|
||||
|
||||
|
||||
if node.position.coordinate != nil {
|
||||
HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 14) {
|
||||
Image(systemName: "mappin").font(.title).foregroundColor(.accentColor)
|
||||
|
|
@ -138,9 +135,9 @@ struct NodeDetail: View {
|
|||
}.padding()
|
||||
Divider()
|
||||
}
|
||||
HStack (alignment: .center) {
|
||||
HStack(alignment: .center) {
|
||||
VStack {
|
||||
HStack{
|
||||
HStack {
|
||||
Image(systemName: "person").font(.title3).foregroundColor(.accentColor)
|
||||
Text("Unique Id:").font(.title3)
|
||||
}
|
||||
|
|
@ -159,15 +156,14 @@ struct NodeDetail: View {
|
|||
}.navigationTitle(node.user.longName)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
|
||||
ZStack {
|
||||
//ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
|
||||
// ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
|
||||
})
|
||||
}.ignoresSafeArea(.all, edges: [.leading, .trailing])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct NodeDetail_Previews: PreviewProvider {
|
||||
static let bleManager = BLEManager()
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct NodeList: View {
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
@State private var selection: String? = nil
|
||||
|
||||
|
||||
@State private var selection: String?
|
||||
|
||||
@State private var showLocationOnly = false
|
||||
|
||||
|
||||
var filteredDevices: [NodeInfoModel] {
|
||||
bleManager.meshData.nodes.filter { node in
|
||||
(!showLocationOnly || node.position.coordinate != nil)
|
||||
|
|
@ -26,52 +26,49 @@ struct NodeList: View {
|
|||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
|
||||
|
||||
List {
|
||||
|
||||
if bleManager.meshData.nodes.count == 0 {
|
||||
Text("Scan for Radios").font(.largeTitle)
|
||||
//.listRowSeparator(.hidden)
|
||||
// .listRowSeparator(.hidden)
|
||||
Text("No LoRa Mesh Nodes Found").font(.title2)
|
||||
//.listRowSeparator(.hidden)
|
||||
// .listRowSeparator(.hidden)
|
||||
Text("Go to the bluetooth section in the bottom right menu and click the Start Scanning button to scan for nearby radios and find your Meshtastic device. Make sure your device is powered on and near your phone or tablet.")
|
||||
.font(.body)
|
||||
//.listRowSeparator(.hidden)
|
||||
// .listRowSeparator(.hidden)
|
||||
Text("Once the device shows under Available Devices touch the device you want to connect to and it will pull node information over BLE and populate the node list and mesh map in the Meshtastic app.")
|
||||
//.listRowSeparator(.hidden)
|
||||
// .listRowSeparator(.hidden)
|
||||
Text("Views with bluetooth functionality will show an indicator in the upper right hand corner show if bluetooth is on, and if a device is connected.")
|
||||
//.listRowSeparator(.hidden)
|
||||
// .listRowSeparator(.hidden)
|
||||
Spacer()
|
||||
//.listRowSeparator(.hidden)
|
||||
}
|
||||
else {
|
||||
// .listRowSeparator(.hidden)
|
||||
} else {
|
||||
Toggle(isOn: $showLocationOnly) {
|
||||
Text("Nodes with location only")
|
||||
}
|
||||
ForEach(filteredDevices.sorted(by: { $0.lastHeard > $1.lastHeard })) { node in
|
||||
|
||||
|
||||
|
||||
let index = filteredDevices.sorted(by: { $0.lastHeard > $1.lastHeard }).firstIndex(where: { $0.id == node.id })
|
||||
|
||||
|
||||
NavigationLink(destination: NodeDetail(node: node), tag: String(index!), selection: $selection) {
|
||||
|
||||
if(bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.myInfo != nil) {
|
||||
|
||||
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.myInfo != nil {
|
||||
|
||||
let connected: Bool = (bleManager.connectedPeripheral.myInfo!.myNodeNum == node.id)
|
||||
NodeRow(node: node, connected: connected)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
NodeRow(node: node, connected: false)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.swipeActions (edge: .trailing) {
|
||||
Button (role: .destructive) {
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button(role: .destructive) {
|
||||
let nodeIndex = bleManager.meshData.nodes.firstIndex(where: { $0.num == node.num })
|
||||
bleManager.meshData.nodes.remove(at: nodeIndex!)
|
||||
bleManager.meshData.save()
|
||||
} label: {
|
||||
|
||||
|
||||
Label("Delete from app", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import MapKit
|
|||
import CoreLocation
|
||||
|
||||
struct NodeMap: View {
|
||||
|
||||
@EnvironmentObject var bleManager :BLEManager
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
var locationNodes: [NodeInfoModel] {
|
||||
bleManager.meshData.nodes.filter { node in
|
||||
(node.position.coordinate != nil)
|
||||
|
|
@ -24,7 +24,7 @@ struct NodeMap: View {
|
|||
let name: String
|
||||
let coordinate: CLLocationCoordinate2D
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
let location = LocationHelper.currentLocation
|
||||
|
||||
|
|
@ -35,15 +35,15 @@ struct NodeMap: View {
|
|||
},
|
||||
set: { _ in }
|
||||
)
|
||||
|
||||
|
||||
NavigationView {
|
||||
|
||||
|
||||
ZStack {
|
||||
Map(coordinateRegion: regionBinding,
|
||||
interactionModes: [.all],
|
||||
showsUserLocation: true,
|
||||
userTrackingMode: .constant(.follow), annotationItems: locationNodes) { location in
|
||||
|
||||
|
||||
MapAnnotation(
|
||||
coordinate: location.position.coordinate!,
|
||||
content: {
|
||||
|
|
@ -51,17 +51,17 @@ struct NodeMap: View {
|
|||
}
|
||||
)
|
||||
}
|
||||
.frame(maxHeight:.infinity)
|
||||
.frame(maxHeight: .infinity)
|
||||
.ignoresSafeArea(.all, edges: [.leading, .trailing])
|
||||
}
|
||||
.navigationTitle("Mesh Map")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
|
||||
ZStack {
|
||||
// ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,51 +5,45 @@ struct NodeRow: View {
|
|||
var connected: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack (alignment: .leading) {
|
||||
|
||||
HStack() {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
HStack {
|
||||
|
||||
CircleText(text: node.user.shortName, color: Color.accentColor).offset(y: 1).padding(.trailing, 5)
|
||||
.offset(x: -15)
|
||||
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
Text(node.user.longName).font(.headline)
|
||||
.offset(x: -15)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(node.user.longName).font(.title)
|
||||
.offset(x: -15)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
|
||||
HStack (alignment: .bottom){
|
||||
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
|
||||
Image(systemName: "clock.badge.checkmark.fill").font(.headline).foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
|
||||
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
|
||||
|
||||
if connected {
|
||||
Text("Currently Connected").font(.caption).foregroundColor(Color.accentColor)
|
||||
}
|
||||
else if node.lastHeard > 0 {
|
||||
} else if node.lastHeard > 0 {
|
||||
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
|
||||
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.caption).foregroundColor(.gray)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Last Heard: Unknown").font(.caption).foregroundColor(.gray)
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if connected {
|
||||
Text("Currently Connected").font(.subheadline).foregroundColor(Color.accentColor)
|
||||
}
|
||||
else if node.lastHeard > 0 {
|
||||
} else if node.lastHeard > 0 {
|
||||
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
|
||||
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.subheadline).foregroundColor(.gray)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text("Last Heard: Unknown").font(.subheadline).foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,38 +4,38 @@ import SwiftUI
|
|||
import SwiftProtobuf
|
||||
|
||||
enum KeyboardType: Int, CaseIterable, Identifiable {
|
||||
|
||||
|
||||
case defaultKeyboard = 0
|
||||
case asciiCapable = 1
|
||||
case twitter = 9
|
||||
case emailAddress = 7
|
||||
case numbersAndPunctuation = 2
|
||||
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
case .defaultKeyboard:
|
||||
return "Default"
|
||||
case .asciiCapable:
|
||||
return "ASCII Capable"
|
||||
case .twitter:
|
||||
return "Twitter"
|
||||
case .emailAddress:
|
||||
return "Email Address"
|
||||
case .numbersAndPunctuation:
|
||||
return "Numbers and Punctuation"
|
||||
case .defaultKeyboard:
|
||||
return "Default"
|
||||
case .asciiCapable:
|
||||
return "ASCII Capable"
|
||||
case .twitter:
|
||||
return "Twitter"
|
||||
case .emailAddress:
|
||||
return "Email Address"
|
||||
case .numbersAndPunctuation:
|
||||
return "Numbers and Punctuation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UserSettings: ObservableObject {
|
||||
//@Published var meshtasticUsername: String {
|
||||
// @Published var meshtasticUsername: String {
|
||||
// didSet {
|
||||
// UserDefaults.standard.set(meshtasticUsername, forKey: "meshtasticusername")
|
||||
// }
|
||||
//}
|
||||
// }
|
||||
@Published var preferredPeripheralName: String {
|
||||
didSet {
|
||||
UserDefaults.standard.set(preferredPeripheralName, forKey: "preferredPeripheralName")
|
||||
|
|
@ -61,9 +61,9 @@ class UserSettings: ObservableObject {
|
|||
UserDefaults.standard.set(meshActivityLog, forKey: "meshActivityLog")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
//self.meshtasticUsername = UserDefaults.standard.object(forKey: "meshtasticusername") as? String ?? ""
|
||||
// self.meshtasticUsername = UserDefaults.standard.object(forKey: "meshtasticusername") as? String ?? ""
|
||||
self.preferredPeripheralName = UserDefaults.standard.object(forKey: "preferredPeripheralName") as? String ?? ""
|
||||
self.preferredPeripheralId = UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? ""
|
||||
self.provideLocation = UserDefaults.standard.object(forKey: "provideLocation") as? Bool ?? false
|
||||
|
|
@ -73,33 +73,33 @@ class UserSettings: ObservableObject {
|
|||
}
|
||||
|
||||
struct AppSettings: View {
|
||||
|
||||
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
|
||||
@State private var preferredDeviceConnected = false
|
||||
|
||||
|
||||
var perferredPeripheral: String {
|
||||
UserDefaults.standard.object(forKey: "preferredPeripheralName") as? String ?? ""
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
NavigationView {
|
||||
|
||||
GeometryReader { bounds in
|
||||
|
||||
|
||||
GeometryReader { _ in
|
||||
|
||||
List {
|
||||
Section(header: Text("USER DETAILS")) {
|
||||
|
||||
//HStack {
|
||||
|
||||
// HStack {
|
||||
// Label("Name", systemImage: "person.crop.rectangle.fill")
|
||||
// TextField("Username", text: $userSettings.meshtasticUsername)
|
||||
// .foregroundColor(.gray)
|
||||
//}
|
||||
//.listRowSeparator(.visible)
|
||||
// }
|
||||
// .listRowSeparator(.visible)
|
||||
Toggle(isOn: $userSettings.provideLocation) {
|
||||
|
||||
|
||||
Label("Provide location to mesh", systemImage: "location.circle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
|
@ -114,7 +114,7 @@ struct AppSettings: View {
|
|||
Text("The preferred radio will automatically reconnect if it becomes disconnected and is still within range. This device is assumed to be the primary radio used for messaging.")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
|
||||
|
||||
}
|
||||
Section(header: Text("MESSAGING OPTIONS")) {
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ struct AppSettings: View {
|
|||
}
|
||||
Section(header: Text("MESH NETWORK OPTIONS")) {
|
||||
Toggle(isOn: $userSettings.meshActivityLog) {
|
||||
|
||||
|
||||
Label("Log all Mesh activity", systemImage: "network")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
|
@ -142,10 +142,9 @@ struct AppSettings: View {
|
|||
}
|
||||
.navigationTitle("App Settings")
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
|
||||
|
||||
ZStack {
|
||||
//ConnectedDevice(bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, name: (self.bleManager.connectedNode != nil) ? self.bleManager.connectedNode.user.shortName : ((self.bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.name : "Unknown") )
|
||||
// ConnectedDevice(bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, name: (self.bleManager.connectedNode != nil) ? self.bleManager.connectedNode.user.shortName : ((self.bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.name : "Unknown") )
|
||||
})
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct LogDocument: FileDocument{
|
||||
static var readableContentTypes:[UTType] {[.plainText]}
|
||||
|
||||
struct LogDocument: FileDocument {
|
||||
static var readableContentTypes: [UTType] {[.plainText]}
|
||||
|
||||
var logFile: String
|
||||
|
||||
init(logFile: String){
|
||||
|
||||
init(logFile: String) {
|
||||
self.logFile = logFile
|
||||
}
|
||||
|
||||
init(configuration: ReadConfiguration) throws{
|
||||
|
||||
init(configuration: ReadConfiguration) throws {
|
||||
guard let data = configuration.file.regularFileContents,
|
||||
let string = String(data: data, encoding: .utf8)
|
||||
else{
|
||||
else {
|
||||
throw CocoaError(.fileReadCorruptFile)
|
||||
}
|
||||
logFile = string
|
||||
}
|
||||
|
||||
|
||||
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
|
||||
return FileWrapper(regularFileWithContents: logFile.data(using: .utf8)!)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ struct MeshLog: View {
|
|||
@State private var logs = [String]()
|
||||
@State private var isExporting: Bool = false
|
||||
@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 {
|
||||
|
||||
|
||||
let url = logFile!
|
||||
logs.removeAll()
|
||||
for try await log in url.lines {
|
||||
|
|
@ -31,10 +31,8 @@ struct MeshLog: View {
|
|||
document: document,
|
||||
contentType: UTType.plainText,
|
||||
defaultFilename: "mesh-activity-log",
|
||||
onCompletion: {
|
||||
onCompletion: { result in
|
||||
|
||||
result in
|
||||
|
||||
if case .success = result {
|
||||
print("Mesh activity log download: success.")
|
||||
} else {
|
||||
|
|
@ -42,12 +40,11 @@ struct MeshLog: View {
|
|||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
.textSelection(.enabled)
|
||||
.font(.caption2)
|
||||
|
||||
HStack (alignment: .center) {
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
let text = ""
|
||||
|
|
@ -57,7 +54,7 @@ struct MeshLog: View {
|
|||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
||||
|
||||
}) {
|
||||
Image(systemName: "trash").imageScale(.large).foregroundColor(.gray)
|
||||
Text("Clear Log").font(.caption)
|
||||
|
|
@ -67,9 +64,9 @@ struct MeshLog: View {
|
|||
.padding()
|
||||
.background(Color(.systemGray6))
|
||||
.clipShape(Capsule())
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
|
||||
Button(action: {
|
||||
isExporting = true
|
||||
}) {
|
||||
|
|
@ -81,9 +78,9 @@ struct MeshLog: View {
|
|||
.padding()
|
||||
.background(Color(.systemGray6))
|
||||
.clipShape(Capsule())
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
.navigationTitle("Mesh Activity Log")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
//@testable import MeshtasticClient
|
||||
// @testable import MeshtasticClient
|
||||
|
||||
class MeshtasticClientTests: XCTestCase {
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
# Meshtastic Client
|
||||
|
||||
- Requires SwiftLint - see https://github.com/realm/SwiftLint
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue