diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj
index 5f4628ec..ac85eaa9 100644
--- a/Meshtastic Client.xcodeproj/project.pbxproj
+++ b/Meshtastic Client.xcodeproj/project.pbxproj
@@ -695,7 +695,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.33;
+ MARKETING_VERSION = 1.35;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@@ -722,7 +722,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.33;
+ MARKETING_VERSION = 1.35;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
diff --git a/Meshtastic Client.xcodeproj/xcuserdata/garthvanderhouwen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Meshtastic Client.xcodeproj/xcuserdata/garthvanderhouwen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index bd8f0435..5acce548 100644
--- a/Meshtastic Client.xcodeproj/xcuserdata/garthvanderhouwen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/Meshtastic Client.xcodeproj/xcuserdata/garthvanderhouwen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -80,22 +80,6 @@
landmarkType = "24">
-
-
-
-
@@ -115,15 +99,15 @@
@@ -131,15 +115,15 @@
diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift
index ea483441..9af3fb15 100644
--- a/MeshtasticClient/Helpers/BLEManager.swift
+++ b/MeshtasticClient/Helpers/BLEManager.swift
@@ -25,7 +25,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
@Published var peripherals = [Peripheral]()
@Published var connectedPeripheral: Peripheral!
- //@Published var connectedNode: NodeInfoEntity!
@Published var lastConnectedPeripheral: String
@Published var lastConnectionError: String
@@ -220,6 +219,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
} catch {
print("💥 Fetch NodeInfo Failed")
+ if meshLoggingEnabled { MeshLogger.log("💥 Fetch NodeInfo Failed") }
}
lastConnectedPeripheral = peripheral.identifier.uuidString
@@ -257,8 +257,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// We will try and re-connect to this device
lastConnectionError = "🚫 \(e.localizedDescription) The app will automatically reconnect to the preferred radio if it reappears within 10 seconds."
if peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" {
- if meshLoggingEnabled { MeshLogger.log("BLE Reconnecting: \(peripheral.name ?? "Unknown")") }
- print("BLE Reconnecting: \(peripheral.name ?? "Unknown")")
+ if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Reconnecting: \(peripheral.name ?? "Unknown")") }
+ print("ℹ️ BLE Reconnecting: \(peripheral.name ?? "Unknown")")
self.connectTo(peripheral: peripheral)
}
} else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us.
@@ -340,7 +340,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
peripheral.readValue(for: FROMRADIO_characteristic)
case FROMNUM_UUID:
- print("FROMNUM (Notify) characteristic OK")
+ print("✅ FROMNUM (Notify) characteristic OK")
if meshLoggingEnabled { MeshLogger.log("✅ BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") }
FROMNUM_characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
@@ -390,14 +390,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
var decodedInfo = FromRadio()
decodedInfo = try! FromRadio(serializedData: characteristic.value!)
- print("Print DecodedInfo")
- print(decodedInfo)
+ //print("Print DecodedInfo")
+ //print(decodedInfo)
// MyInfo Data
if decodedInfo.myInfo.myNodeNum != 0 {
- print("💾 Save a CoreData MyInfoEntity")
-
let fetchMyInfoRequest:NSFetchRequest = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.myInfo.myNodeNum))
@@ -413,6 +411,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
myInfo.messageTimeoutMsec = Int32(bitPattern: decodedInfo.myInfo.messageTimeoutMsec)
myInfo.minAppVersion = Int32(bitPattern: decodedInfo.myInfo.minAppVersion)
myInfo.maxChannels = Int32(bitPattern: decodedInfo.myInfo.maxChannels)
+ connectedPeripheral.num = myInfo.myNodeNum
+ connectedPeripheral.firmwareVersion = myInfo.firmwareVersion ?? "Unknown"
+
}
else {
@@ -439,17 +440,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
} catch {
- print("💥 Fetch MyInfo Error")
+ print("💥 Fetch MyInfo Error")
}
-
}
// NodeInfo Data
if decodedInfo.nodeInfo.num != 0 {
- print("💾 Save a CoreData NodeInfoEntity")
-
let fetchNodeRequest:NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.nodeInfo.num))
@@ -469,12 +467,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if self.connectedPeripheral != nil && self.connectedPeripheral.num == newNode.id {
- newNode.bleName = self.connectedPeripheral.name
-
- } else {
-
- let userIdLast4: String = String(decodedInfo.nodeInfo.user.id.suffix(4))
- newNode.bleName = "Meshtastic_" + userIdLast4
+ newNode.bleName = self.connectedPeripheral.peripheral.name
+ if decodedInfo.nodeInfo.hasUser {
+
+ connectedPeripheral.name = decodedInfo.nodeInfo.user.longName
+ connectedPeripheral.longName = decodedInfo.nodeInfo.user.longName
+ connectedPeripheral.shortName = decodedInfo.nodeInfo.user.shortName
+ }
}
if decodedInfo.nodeInfo.hasUser {
@@ -486,6 +485,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
newUser.shortName = decodedInfo.nodeInfo.user.shortName
newUser.macaddr = decodedInfo.nodeInfo.user.macaddr
newUser.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
+ newUser.team = (String(describing: decodedInfo.nodeInfo.user.team))
newNode.user = newUser
}
@@ -530,6 +530,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
fetchedNode[0].user!.longName = decodedInfo.nodeInfo.user.longName
fetchedNode[0].user!.shortName = decodedInfo.nodeInfo.user.shortName
fetchedNode[0].user!.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
+ fetchedNode[0].user!.team = (String(describing: decodedInfo.nodeInfo.user.team))
}
let position = PositionEntity(context: context!)
@@ -625,9 +626,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if decodedInfo.packet.to == broadcastNodeNum && fetchedUsers.count == 1 {
+ // Save the broadcast user if it does not exist
let bcu: UserEntity = UserEntity(context: context!)
- bcu.shortName = "BC"
- bcu.longName = "Broadcast"
+ bcu.shortName = "ALL"
+ bcu.longName = "Broadcast (^all)"
bcu.hwModel = "UNSET"
bcu.num = Int64(broadcastNodeNum)
bcu.userId = "BROADCASTNODE"
@@ -693,12 +695,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
return
}
do {
- // print(decodedInfo.packet.decoded.payload)
+
try context!.save()
- if meshLoggingEnabled {
- MeshLogger.log("💾 Updated NodeInfo SNR and Time from Node Info App Packet For: \(Int64(decodedInfo.nodeInfo.num))")
- }
+ if meshLoggingEnabled { MeshLogger.log("💾 Updated NodeInfo SNR and Time from Node Info App Packet For: \(Int64(decodedInfo.nodeInfo.num))")}
print("💾 Updated NodeInfo SNR and Time from Packet For: \(fetchedNode[0].num)")
} catch {
@@ -714,8 +714,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("💥 Error Fetching NodeInfoEntity for NODEINFO_APP")
}
- print(decodedInfo.packet.decoded.payload)
-
} else if decodedInfo.packet.decoded.portnum == PortNum.positionApp {
let fetchNodePositionRequest:NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity")
@@ -728,7 +726,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if fetchedNode.count == 1 {
fetchedNode[0].id = Int64(decodedInfo.packet.from)
fetchedNode[0].num = Int64(decodedInfo.packet.from)
- print(decodedInfo.packet.decoded.payload)
if(decodedInfo.packet.rxTime == 0) {
fetchedNode[0].lastHeard = Date()
@@ -830,9 +827,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
success = false
} else if message.count < 1 {
- // Don's send an empty message
- print("Don't Send an Empty Message")
+
+ // Don't send an empty message
+ print("🚫 Don't Send an Empty Message")
success = false
+
} else {
let fromUserNum:Int64 = self.connectedPeripheral.num
@@ -846,7 +845,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if fetchedUsers.isEmpty {
- print("Message Users Not Found, Fail")
+ print("🚫 Message Users Not Found, Fail")
success = false
}
else if fetchedUsers.count >= 1 {
@@ -860,8 +859,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if newMessage.toUser == nil {
let bcu: UserEntity = UserEntity(context: context!)
- bcu.shortName = "BC"
- bcu.longName = "Broadcast"
+ bcu.shortName = "ALL"
+ bcu.longName = "Broadcast (^all)"
bcu.hwModel = "UNSET"
bcu.num = Int64(broadcastNodeNum)
bcu.userId = "BROADCASTNODE"
@@ -888,6 +887,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
toRadio.packet = meshPacket
let binaryData: Data = try! toRadio.serializedData()
+
+ if meshLoggingEnabled { MeshLogger.log("📲 New message sent to \(newMessage.toUser?.longName! ?? "Unknown")") }
+ print("📲 New message sent to \(newMessage.toUser?.longName! ?? "Unknown")")
+
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
do {
@@ -903,7 +906,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
context!.rollback()
let nsError = error as NSError
- print("Unresolved error \(nsError)")
+ print("🚫 Unresolved error \(nsError)")
}
}
}
diff --git a/MeshtasticClient/Meshtastic.xcdatamodeld/CoreDataSample.xcdatamodel/contents b/MeshtasticClient/Meshtastic.xcdatamodeld/CoreDataSample.xcdatamodel/contents
index b966753b..3cce2d60 100644
--- a/MeshtasticClient/Meshtastic.xcdatamodeld/CoreDataSample.xcdatamodel/contents
+++ b/MeshtasticClient/Meshtastic.xcdatamodeld/CoreDataSample.xcdatamodel/contents
@@ -58,6 +58,7 @@
+
@@ -68,6 +69,6 @@
-
+
\ No newline at end of file
diff --git a/MeshtasticClient/MeshtasticClientApp.swift b/MeshtasticClient/MeshtasticClientApp.swift
index 66a2c13d..8bf762bc 100644
--- a/MeshtasticClient/MeshtasticClientApp.swift
+++ b/MeshtasticClient/MeshtasticClientApp.swift
@@ -21,22 +21,22 @@ struct MeshtasticClientApp: App {
.onChange(of: scenePhase) { (newScenePhase) in
switch newScenePhase {
case .background:
+ print("ℹ️ Scene is in the background")
do {
try persistenceController.container.viewContext.save()
- print("Saved viewContext when the app went to the background.")
+ print("💾 Saved CoreData ViewContext when the app went to the background.")
} catch {
- print("Failed to save viewContext when the app goes to the background.")
+ print("💥 Failed to save viewContext when the app goes to the background.")
}
- print("Scene is in the background")
case .inactive:
- print("Scene is inactive")
+ print("ℹ️ Scene is inactive")
case .active:
- print("Scene is active")
+ print("ℹ️ Scene is active")
@unknown default:
- print("Apple must have changed something")
+ print("💥 Apple must have changed something")
}
}
}
diff --git a/MeshtasticClient/Views/ContentView.swift b/MeshtasticClient/Views/ContentView.swift
index f950a0fc..ca20500d 100644
--- a/MeshtasticClient/Views/ContentView.swift
+++ b/MeshtasticClient/Views/ContentView.swift
@@ -8,6 +8,7 @@ struct ContentView: View {
@State private var selection: Tab = .ble
enum Tab {
+ case contacts
case messages
case map
case ble
@@ -18,6 +19,14 @@ struct ContentView: View {
var body: some View {
TabView(selection: $selection) {
+// Contacts()
+// .tabItem {
+// Label("Contacts", systemImage: "person.crop.circle")
+// .symbolRenderingMode(.hierarchical)
+// .symbolVariant(.none)
+//
+// }
+// .tag(Tab.contacts)
Channels()
.tabItem {
Label("Messages", systemImage: "text.bubble")
diff --git a/MeshtasticClient/Views/Messages/Contacts.swift b/MeshtasticClient/Views/Messages/Contacts.swift
index 66093924..8f071694 100644
--- a/MeshtasticClient/Views/Messages/Contacts.swift
+++ b/MeshtasticClient/Views/Messages/Contacts.swift
@@ -8,8 +8,91 @@
import SwiftUI
struct Contacts: View {
+
+ @Environment(\.managedObjectContext) var context
+ @EnvironmentObject var bleManager: BLEManager
+
+ @FetchRequest(
+ sortDescriptors: [NSSortDescriptor(key: "longName", ascending: true)],
+ animation: .default)
+
+ private var users: FetchedResults
+
var body: some View {
- Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
+ NavigationView {
+ List(users) { user in
+
+ if user.receivedMessages?.count ?? 0 > 0 {
+
+ let mostRecent = user.receivedMessages?.lastObject as! MessageEntity
+ let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64(mostRecent.messageTimestamp)))
+ let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0
+ let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0
+
+ HStack {
+ VStack {
+ CircleText(text: user.shortName ?? "???", color: Color.blue)
+ }
+ VStack {
+
+ HStack (alignment: .bottom){
+
+ VStack {
+ Text(user.longName ?? "Unknown").font(.headline)
+ }
+
+ VStack {
+ if lastMessageDay == currentDay {
+
+ Text(lastMessageTime, style: .time )
+ .font(.caption)
+ .foregroundColor(.gray)
+
+ } else if ( lastMessageDay == (currentDay - 1)) {
+
+ Text("Yesterday")
+ .font(.callout)
+ .foregroundColor(.gray)
+
+ } else if ( lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) ) {
+
+ Text(lastMessageTime, style: .date)
+
+ } else {
+
+ Text(lastMessageTime, style: .date)
+ }
+ }.frame(maxWidth: .infinity, alignment: .trailing)
+ }
+ .listRowSeparator(.hidden).frame(height: 5)
+ HStack (alignment: .top) {
+
+ Text(mostRecent.messagePayload ?? "EMPTY MESSSAGE")
+ .frame(height: 60)
+ .truncationMode(.tail)
+ }
+ }
+ }.padding(10)
+ } else {
+ HStack {
+ VStack {
+ CircleText(text: user.shortName ?? "???", color: Color.blue)
+ }
+ VStack {
+
+ HStack{
+
+ VStack {
+ Text(user.longName ?? "Unknown").font(.title3)
+ }
+ }
+ }
+ }.padding()
+ }
+ //NavigationLink(note.title, destination: NoteEditor(id: note.id))
+ }
+ .navigationTitle("Contacts")
+ }
}
}
diff --git a/MeshtasticClient/Views/Nodes/NodeDetail.swift b/MeshtasticClient/Views/Nodes/NodeDetail.swift
index d491a887..eec2b014 100644
--- a/MeshtasticClient/Views/Nodes/NodeDetail.swift
+++ b/MeshtasticClient/Views/Nodes/NodeDetail.swift
@@ -175,7 +175,7 @@ struct NodeDetail: View {
}
}.padding()
- if node.positions?.count ?? 0 > 0 {
+ if node.positions?.count ?? 0 > 1 {
Divider()
@@ -193,52 +193,51 @@ struct NodeDetail: View {
ForEach(node.positions!.array as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in
- //if mappin.coordinate != nil {
+ if mappin.coordinate != nil {
VStack {
- HStack {
-
- Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) //.font(.subheadline)
- Text("Lat/Long:").font(.caption)
- Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))")
- .foregroundColor(.gray)
- .font(.caption)
+ HStack {
- Text("Altitude:")
- .font(.caption)
-
- Text("\(String(mappin.altitude))m")
- .foregroundColor(.gray)
- .font(.caption)
+ Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) //.font(.subheadline)
+ Text("Lat/Long:").font(.caption)
+ Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))")
+ .foregroundColor(.gray)
+ .font(.caption)
+
+ Text("Altitude:")
+ .font(.caption)
+
+ Text("\(String(mappin.altitude))m")
+ .foregroundColor(.gray)
+ .font(.caption)
+ }
+ HStack {
+
+ Image(systemName: "clock.badge.checkmark.fill")
+ .font(.subheadline)
+ .foregroundColor(.accentColor)
+ .symbolRenderingMode(.hierarchical)
+ Text("Time:")
+ .font(.caption)
+ Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)")
+ .foregroundColor(.gray)
+ .font(.caption)
+ Divider()
+
+ Text("Battery").font(.caption).fixedSize()
+ Text(String(mappin.batteryLevel) + "%")
+ .font(.caption)
+ .foregroundColor(.gray)
+ .symbolRenderingMode(.hierarchical)
+ }
}
- HStack {
-
- Image(systemName: "clock.badge.checkmark.fill")
- .font(.subheadline)
- .foregroundColor(.accentColor)
- .symbolRenderingMode(.hierarchical)
- Text("Time:")
- .font(.caption)
- Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)")
- .foregroundColor(.gray)
- .font(.caption)
- Divider()
-
- Text("Battery").font(.caption).fixedSize()
- Text(String(mappin.batteryLevel) + "%")
- .font(.caption)
- .foregroundColor(.gray)
- .symbolRenderingMode(.hierarchical)
- }
- }
.padding(1)
Divider()
- //}
+ }
}
.padding(.bottom, 5) // Without some padding here there is a transparent contentview bug
}
-
}
}
.navigationTitle(node.user!.longName ?? "Unknown")