From 92c61f199f7c3d81d6fcfdb2f2020db3e2891e82 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 21 Dec 2021 22:50:37 -0800 Subject: [PATCH 1/3] Image updates, emoji in the logs logging for the message send function --- Meshtastic Client.xcodeproj/project.pbxproj | 8 ++- .../xcdebugger/Breakpoints_v2.xcbkptlist | 56 +++++++++------ MeshtasticClient/Helpers/BLEManager.swift | 70 ++++++++++--------- .../Views/Messages/Contacts.swift | 20 ++++++ .../Views/Messages/Messages.swift | 1 - 5 files changed, 98 insertions(+), 57 deletions(-) create mode 100644 MeshtasticClient/Views/Messages/Contacts.swift diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index af7c9c5e..5f4628ec 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */; }; DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FE272476C700F4AB02 /* LogDocument.swift */; }; DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD836AE626F6B38600ABCC23 /* Connect.swift */; }; + DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD882F5C2772E4640005BF05 /* Contacts.swift */; }; DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860B26F684AF00DC5189 /* BatteryIcon.swift */; }; DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; }; DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; }; @@ -82,6 +83,7 @@ DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = ""; }; DD8169FE272476C700F4AB02 /* LogDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDocument.swift; sourceTree = ""; }; DD836AE626F6B38600ABCC23 /* Connect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connect.swift; sourceTree = ""; }; + DD882F5C2772E4640005BF05 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = ""; }; DD90860A26F645B700DC5189 /* MeshtasticClient.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MeshtasticClient.entitlements; sourceTree = ""; }; DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = ""; }; DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = ""; }; @@ -293,6 +295,7 @@ children = ( DD47E3DA26F3901A00029299 /* Channels.swift */, DD47E3DC26F390A000029299 /* Messages.swift */, + DD882F5C2772E4640005BF05 /* Contacts.swift */, ); path = Messages; sourceTree = ""; @@ -506,6 +509,7 @@ DDAF8C5D26ED09490058C060 /* portnums.pb.swift in Sources */, DD9D8F2F2764403B00080993 /* Meshtastic.xcdatamodeld in Sources */, DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */, + DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */, DD47E3CE26F103C600029299 /* NodeList.swift in Sources */, DD47E3D626F17ED900029299 /* CircleText.swift in Sources */, DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */, @@ -691,7 +695,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.32; + MARKETING_VERSION = 1.33; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -718,7 +722,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.32; + MARKETING_VERSION = 1.33; 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 a69d2766..bd8f0435 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"> - - - - @@ -122,11 +106,43 @@ filePath = "MeshtasticClient/Helpers/BLEManager.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "893" - endingLineNumber = "893" + startingLineNumber = "894" + endingLineNumber = "894" landmarkName = "sendMessage(message:toUserNum:)" landmarkType = "7"> + + + + + + + + diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 7ad8f118..ea483441 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -55,7 +55,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // MARK: init BLEManager override init() { - self.meshLoggingEnabled = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false + self.meshLoggingEnabled = true // UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? true self.lastConnectedPeripheral = "" self.lastConnectionError = "" super.init() @@ -341,7 +341,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph case FROMNUM_UUID: print("FROMNUM (Notify) characteristic OK") - if meshLoggingEnabled { MeshLogger.log("βœ…BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") } + if meshLoggingEnabled { MeshLogger.log("βœ… BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") } FROMNUM_characteristic = characteristic peripheral.setNotifyValue(true, for: characteristic) @@ -457,7 +457,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph let fetchedNode = try context?.fetch(fetchNodeRequest) as! [NodeInfoEntity] // Not Found Insert - if fetchedNode.isEmpty { + if fetchedNode.isEmpty && decodedInfo.nodeInfo.hasUser { let newNode = NodeInfoEntity(context: context!) newNode.id = Int64(decodedInfo.nodeInfo.num) @@ -517,7 +517,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph print("πŸ’₯ Fetch MyInfo Error") } - } else { + } else if decodedInfo.nodeInfo.hasUser { fetchedNode[0].id = Int64(decodedInfo.nodeInfo.num) fetchedNode[0].num = Int64(decodedInfo.nodeInfo.num) @@ -600,17 +600,15 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // Handle assorted app packets if decodedInfo.packet.id != 0 { - print("Handle a Packet") do { - //!!!: Switch Messages Tab to coredata // Text Message App - Primary Broadcast Channel if decodedInfo.packet.decoded.portnum == PortNum.textMessageApp { if let messageText = String(bytes: decodedInfo.packet.decoded.payload, encoding: .utf8) { - print("Message Text: \(messageText)") - if meshLoggingEnabled { MeshLogger.log("BLE FROMRADIO received for text message app \(messageText)") } + print("πŸ’¬ BLE FROMRADIO received for text message app \(messageText)") + if meshLoggingEnabled { MeshLogger.log("πŸ’¬ BLE FROMRADIO received for text message app \(messageText)") } let messageUsers:NSFetchRequest = NSFetchRequest.init(entityName: "UserEntity") messageUsers.predicate = NSPredicate(format:"num IN %@", [decodedInfo.packet.to, decodedInfo.packet.from]) @@ -624,7 +622,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph newMessage.messageTimestamp = Int32(bitPattern: decodedInfo.packet.rxTime) newMessage.receivedACK = false newMessage.direction = "IN" - //newMessage.toUser = Int64(decodedInfo.packet.to) if decodedInfo.packet.to == broadcastNodeNum && fetchedUsers.count == 1 { @@ -647,7 +644,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph do { try context!.save() - print("Saved a new message for \(decodedInfo.packet.id)") + print("πŸ’Ύ Saved a new message for \(decodedInfo.packet.id)") + if meshLoggingEnabled { MeshLogger.log("πŸ’Ύ Saved a new message for \(decodedInfo.packet.id)") } // Create an iOS Notification for the received message and schedule it immediately let manager = LocalNotificationManager() @@ -660,19 +658,19 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph content: messageText) ] manager.schedule() - if meshLoggingEnabled { MeshLogger.log("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "Unknown") \(messageText)") } + if meshLoggingEnabled { MeshLogger.log("πŸ’¬ iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "Unknown") \(messageText)") } } catch { context!.rollback() let nsError = error as NSError - print("Failed to save new MessageEntity \(nsError)") + print("πŸ’₯ Failed to save new MessageEntity \(nsError)") } } catch { - print("Fetch Message To and From Users Error") + print("πŸ’₯ Fetch Message To and From Users Error") } } } else if decodedInfo.packet.decoded.portnum == PortNum.nodeinfoApp { @@ -699,21 +697,21 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph try context!.save() if meshLoggingEnabled { - MeshLogger.log("MESH PACKET Updated NodeInfo SNR and Time from Node Info App Packet For: \(Int64(decodedInfo.nodeInfo.num))") + 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)") + print("πŸ’Ύ Updated NodeInfo SNR and Time from Packet For: \(fetchedNode[0].num)") } catch { context!.rollback() let nsError = error as NSError - print("Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") + print("πŸ’₯ Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") } } catch { - print("Error Fetching NodeInfoEntity for NODEINFO_APP") + print("πŸ’₯ Error Fetching NodeInfoEntity for NODEINFO_APP") } print(decodedInfo.packet.decoded.payload) @@ -760,32 +758,33 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph context!.rollback() let nsError = error as NSError - print("Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") + print("πŸ’₯ Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") } } catch { - print("Error Fetching NodeInfoEntity for NODEINFO_APP") + print("πŸ’₯ Error Fetching NodeInfoEntity for NODEINFO_APP") } } else if decodedInfo.packet.decoded.portnum == PortNum.adminApp { - if meshLoggingEnabled { MeshLogger.log("MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("Admin App Packet") - print(try decodedInfo.packet.jsonString()) + if meshLoggingEnabled { MeshLogger.log("🚨 MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") } + print("🚨 MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") + } else if decodedInfo.packet.decoded.portnum == PortNum.routingApp { - if meshLoggingEnabled { MeshLogger.log("MESH PACKET received for Routing App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("Routing App Packet") - print(try decodedInfo.packet.jsonString()) + if meshLoggingEnabled { MeshLogger.log("🚨 MESH PACKET received for Routing App UNHANDLED \(try decodedInfo.packet.jsonString())") } + print("🚨 MESH PACKET received for Routing App UNHANDLED \(try decodedInfo.packet.jsonString())") + } else { - if meshLoggingEnabled { MeshLogger.log("MESH PACKET received for Other App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("Other App Packet") - print(try decodedInfo.packet.jsonString()) + + if meshLoggingEnabled { MeshLogger.log("🚨 MESH PACKET received for Other App UNHANDLED \(try decodedInfo.packet.jsonString())") } + print("🚨 MESH PACKET received for Other App UNHANDLED \(try decodedInfo.packet.jsonString())") + } } catch { - if meshLoggingEnabled { MeshLogger.log("Fatal Error: Failed to decode json") } - fatalError("Failed to decode json") + if meshLoggingEnabled { MeshLogger.log("⚰️ Fatal Error: Failed to decode json") } + print("⚰️ Fatal Error: Failed to decode json") } } @@ -798,8 +797,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } default: - if meshLoggingEnabled { MeshLogger.log("Unhandled Characteristic UUID: \(characteristic.uuid)") } - print("Unhandled Characteristic UUID: \(characteristic.uuid)") + if meshLoggingEnabled { MeshLogger.log("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)") } + print("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)") } peripheral.readValue(for: FROMRADIO_characteristic) } @@ -826,7 +825,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph connectTo(peripheral: lastConnectedPeripheral!.peripheral) } } - print("Failed in the top message condition") + print("🚫 Message Send Failed, not properly connected to \(lastConnectedPeripheral)") + if meshLoggingEnabled { MeshLogger.log("🚫 Message Send Failed, not properly connected to \(lastConnectedPeripheral)") } + success = false } else if message.count < 1 { // Don's send an empty message @@ -892,7 +893,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph do { try context!.save() - print("Saved a new sent message from \(connectedPeripheral.num)") + print("πŸ’Ύ Saved a new sent message from \(newMessage.fromUser?.longName! ?? "Unknown")") + if meshLoggingEnabled { MeshLogger.log("πŸ’Ύ Saved a new sent message from \(connectedPeripheral.num)") } success = true nextSentMessageId+=1 diff --git a/MeshtasticClient/Views/Messages/Contacts.swift b/MeshtasticClient/Views/Messages/Contacts.swift new file mode 100644 index 00000000..66093924 --- /dev/null +++ b/MeshtasticClient/Views/Messages/Contacts.swift @@ -0,0 +1,20 @@ +// +// Contacts.swift +// MeshtasticClient +// +// Created by Garth Vander Houwen on 12/21/21. +// + +import SwiftUI + +struct Contacts: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct Contacts_Previews: PreviewProvider { + static var previews: some View { + Contacts() + } +} diff --git a/MeshtasticClient/Views/Messages/Messages.swift b/MeshtasticClient/Views/Messages/Messages.swift index 92a1d1a6..990f13a4 100644 --- a/MeshtasticClient/Views/Messages/Messages.swift +++ b/MeshtasticClient/Views/Messages/Messages.swift @@ -49,7 +49,6 @@ struct Messages: View { HStack(alignment: .top) { let currentUser: Bool = (bleManager.connectedPeripheral == nil) ? false : ((bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.num == message.fromUser?.num) ? true : false ) - //let currentUser: (Bool = message.fromUser == nil : false : (message.fromUser != nil && bleManager.connectedPeripheral.num == message.fromUser!.num : true) CircleText(text: (message.fromUser?.shortName ?? "???"), color: currentUser ? .accentColor : Color(.darkGray)).padding(.all, 5) .gesture(LongPressGesture(minimumDuration: 2) From a8d08c0b9f83abeac8561b5fc101ea505a3596c0 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 24 Dec 2021 21:50:10 -0800 Subject: [PATCH 2/3] V 1.35 Connected Peripheral and MyInfo bugs --- Meshtastic Client.xcodeproj/project.pbxproj | 4 +- .../xcdebugger/Breakpoints_v2.xcbkptlist | 32 ++----- MeshtasticClient/Helpers/BLEManager.swift | 69 ++++++++------- .../CoreDataSample.xcdatamodel/contents | 3 +- MeshtasticClient/MeshtasticClientApp.swift | 12 +-- MeshtasticClient/Views/ContentView.swift | 9 ++ .../Views/Messages/Contacts.swift | 85 ++++++++++++++++++- MeshtasticClient/Views/Nodes/NodeDetail.swift | 73 ++++++++-------- 8 files changed, 183 insertions(+), 104 deletions(-) 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") From 3161eecb5bc6ded50992076563f461d3d0f4c62c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 24 Dec 2021 23:41:18 -0800 Subject: [PATCH 3/3] V 1.36 BLE Stability Updates and Finished Contacts List --- Meshtastic Client.xcodeproj/project.pbxproj | 8 +++- .../xcdebugger/Breakpoints_v2.xcbkptlist | 48 ++++++++++++------- MeshtasticClient/Helpers/BLEManager.swift | 5 +- .../Views/Messages/Contacts.swift | 43 +++++++++++++---- .../Views/Messages/UserMessageList.swift | 20 ++++++++ 5 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 MeshtasticClient/Views/Messages/UserMessageList.swift diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index ac85eaa9..e91bf92c 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */; }; DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */; }; DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E65252767A01F00E45FC5 /* NodeDetail.swift */; }; DD47E3CE26F103C600029299 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeList.swift */; }; @@ -68,6 +69,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserMessageList.swift; sourceTree = ""; }; DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = ""; }; DD2E65252767A01F00E45FC5 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = ""; }; DD47E3CD26F103C600029299 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = ""; }; @@ -296,6 +298,7 @@ DD47E3DA26F3901A00029299 /* Channels.swift */, DD47E3DC26F390A000029299 /* Messages.swift */, DD882F5C2772E4640005BF05 /* Contacts.swift */, + DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */, ); path = Messages; sourceTree = ""; @@ -508,6 +511,7 @@ DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */, DDAF8C5D26ED09490058C060 /* portnums.pb.swift in Sources */, DD9D8F2F2764403B00080993 /* Meshtastic.xcdatamodeld in Sources */, + DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */, DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */, DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */, DD47E3CE26F103C600029299 /* NodeList.swift in Sources */, @@ -695,7 +699,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.35; + MARKETING_VERSION = 1.36; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -722,7 +726,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.35; + MARKETING_VERSION = 1.36; 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 5acce548..40af0c6f 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"> - - - - + + + + + + + + diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 9af3fb15..0f2ba231 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -473,6 +473,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph connectedPeripheral.name = decodedInfo.nodeInfo.user.longName connectedPeripheral.longName = decodedInfo.nodeInfo.user.longName connectedPeripheral.shortName = decodedInfo.nodeInfo.user.shortName + connectedPeripheral.num = Int64(decodedInfo.nodeInfo.num) } } @@ -629,7 +630,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // Save the broadcast user if it does not exist let bcu: UserEntity = UserEntity(context: context!) bcu.shortName = "ALL" - bcu.longName = "Broadcast (^all)" + bcu.longName = "Primary - Broadcast" bcu.hwModel = "UNSET" bcu.num = Int64(broadcastNodeNum) bcu.userId = "BROADCASTNODE" @@ -860,7 +861,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph let bcu: UserEntity = UserEntity(context: context!) bcu.shortName = "ALL" - bcu.longName = "Broadcast (^all)" + bcu.longName = "Primary - Broadcast" bcu.hwModel = "UNSET" bcu.num = Int64(broadcastNodeNum) bcu.userId = "BROADCASTNODE" diff --git a/MeshtasticClient/Views/Messages/Contacts.swift b/MeshtasticClient/Views/Messages/Contacts.swift index 8f071694..fbb05da6 100644 --- a/MeshtasticClient/Views/Messages/Contacts.swift +++ b/MeshtasticClient/Views/Messages/Contacts.swift @@ -16,10 +16,12 @@ struct Contacts: View { sortDescriptors: [NSSortDescriptor(key: "longName", ascending: true)], animation: .default) - private var users: FetchedResults + private var users: FetchedResults var body: some View { + NavigationView { + List(users) { user in if user.receivedMessages?.count ?? 0 > 0 { @@ -30,18 +32,24 @@ struct Contacts: View { let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0 HStack { - VStack { - CircleText(text: user.shortName ?? "???", color: Color.blue) - } + VStack { - HStack (alignment: .bottom){ + CircleText(text: user.shortName ?? "???", color: Color.blue) + } + .padding([.leading, .trailing]) + + VStack { + + HStack { VStack { - Text(user.longName ?? "Unknown").font(.headline) + + Text(user.longName ?? "Unknown").font(.headline).fixedSize() } VStack { + if lastMessageDay == currentDay { Text(lastMessageTime, style: .time ) @@ -65,27 +73,41 @@ struct Contacts: View { }.frame(maxWidth: .infinity, alignment: .trailing) } .listRowSeparator(.hidden).frame(height: 5) + HStack (alignment: .top) { - Text(mostRecent.messagePayload ?? "EMPTY MESSSAGE") .frame(height: 60) .truncationMode(.tail) + .foregroundColor(Color.gray) + .frame(maxWidth: .infinity, alignment: .leading) } - } - }.padding(10) + }.padding(.top, 15) + } } else { + HStack { + VStack { + CircleText(text: user.shortName ?? "???", color: Color.blue) } + .padding(.trailing) + VStack { HStack{ VStack { - Text(user.longName ?? "Unknown").font(.title3) + + Text(user.longName ?? "Unknown").font(.headline).fixedSize() } + + VStack { + Text(" ") + } + .frame(maxWidth: .infinity, alignment: .trailing) } + .listRowSeparator(.hidden).frame(height: 5) } }.padding() } @@ -93,6 +115,7 @@ struct Contacts: View { } .navigationTitle("Contacts") } + .listStyle(PlainListStyle()) } } diff --git a/MeshtasticClient/Views/Messages/UserMessageList.swift b/MeshtasticClient/Views/Messages/UserMessageList.swift new file mode 100644 index 00000000..56411298 --- /dev/null +++ b/MeshtasticClient/Views/Messages/UserMessageList.swift @@ -0,0 +1,20 @@ +// +// UserMessageList.swift +// MeshtasticClient +// +// Created by Garth Vander Houwen on 12/24/21. +// + +import SwiftUI + +struct UserMessageList: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct UserMessageList_Previews: PreviewProvider { + static var previews: some View { + UserMessageList() + } +}