Merge branch 'main' into formatting_merge_conficts

This commit is contained in:
Garth Vander Houwen 2021-11-29 20:06:27 -08:00 committed by GitHub
commit 68bdb82aa2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 888 additions and 895 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.DS_Store

48
.swiftlint.yml Normal file
View 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

View file

@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

View 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

View file

@ -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)
}
}
}

View file

@ -7,5 +7,3 @@
import Foundation
import SwiftUI

View file

@ -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 {

View file

@ -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)")
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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")
]
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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()

View file

@ -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")
]
}

View file

@ -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")
]
}

View file

@ -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")
]
}

View file

@ -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
}
})

View file

@ -16,7 +16,7 @@ struct ContentView: View {
}
var body: some View {
TabView(selection: $selection) {
Channels()
.tabItem {

View file

@ -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)

View file

@ -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))
}
}

View file

@ -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))
}
}

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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()

View file

@ -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")
}
}

View file

@ -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())
}

View file

@ -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)
}
}

View file

@ -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())

View file

@ -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)!)
}

View file

@ -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")

View file

@ -6,7 +6,7 @@
//
import XCTest
//@testable import MeshtasticClient
// @testable import MeshtasticClient
class MeshtasticClientTests: XCTestCase {

View file

@ -1 +1,3 @@
# Meshtastic Client
- Requires SwiftLint - see https://github.com/realm/SwiftLint