From bed7c5ce5cd32669b5886a774ac4759d2ec87c9c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 28 Dec 2021 09:11:24 -0800 Subject: [PATCH] Messages bug fix --- Meshtastic Client.xcodeproj/project.pbxproj | 4 +- MeshtasticClient/Helpers/BLEManager.swift | 12 +- MeshtasticClient/Helpers/Extensions.swift | 4 + .../Persistence/Persistence.swift | 18 +- MeshtasticClient/Views/ContentView.swift | 28 +- .../Views/Messages/Channels.swift | 88 ++-- .../Views/Messages/Contacts.swift | 276 ++++++------ .../Views/Messages/UserMessageList.swift | 402 +++++++++--------- MeshtasticClient/Views/Nodes/NodeDetail.swift | 6 +- 9 files changed, 429 insertions(+), 409 deletions(-) diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index 7a116f72..5d0413b6 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -719,7 +719,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.37; + MARKETING_VERSION = 1.38; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -746,7 +746,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.37; + MARKETING_VERSION = 1.38; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 053a874b..4bdaab45 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -36,7 +36,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph var timeoutTimerCount = 0 let broadcastNodeNum: UInt32 = 4294967295 - var nextSentMessageId: Int64 = 1 /* Meshtastic Service Details */ var TORADIO_characteristic: CBCharacteristic! @@ -632,7 +631,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 = "ALL - Broadcast" + bcu.longName = "All - Broadcast" bcu.hwModel = "UNSET" bcu.num = Int64(broadcastNodeNum) bcu.userId = "BROADCASTNODE" @@ -862,7 +861,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } else if fetchedUsers.count >= 1 { let newMessage = MessageEntity(context: context!) - newMessage.messageId = Int64.random(in: Int64.min.. String { - return String(data: Data(bytes: array, count: array.count), encoding: .utf8) ?? "" -} diff --git a/MeshtasticClient/Helpers/Extensions.swift b/MeshtasticClient/Helpers/Extensions.swift index 8f7eb6ee..e1493d4a 100644 --- a/MeshtasticClient/Helpers/Extensions.swift +++ b/MeshtasticClient/Helpers/Extensions.swift @@ -5,6 +5,10 @@ extension Data { var hexDescription: String { return reduce("") {$0 + String(format: "%02x", $1)} } + var macAddressString: String { + let mac: String = reduce("") {$0 + String(format: "%02x:", $1)} + return String(mac.dropLast()) + } } extension Date { diff --git a/MeshtasticClient/Persistence/Persistence.swift b/MeshtasticClient/Persistence/Persistence.swift index 4b5cee4b..9168f07d 100644 --- a/MeshtasticClient/Persistence/Persistence.swift +++ b/MeshtasticClient/Persistence/Persistence.swift @@ -39,7 +39,8 @@ class PersistenceController { container.loadPersistentStores(completionHandler: { (_, error) in // Merge policy that favors in memory data over data in the db self.container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - + + if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. @@ -52,7 +53,20 @@ class PersistenceController { * The store could not be migrated to the current model version. Check the error message to determine what the actual problem was. */ - fatalError("Unresolved error \(error), \(error.userInfo)") + + let firstStoreURL = self.container.persistentStoreCoordinator.persistentStores.first?.url + + do { + + try self.container.persistentStoreCoordinator.destroyPersistentStore(at: firstStoreURL!, type: .sqlite, options: nil) + + print("💥 Something went terribly wrong, CoreData database truncated. All app data is lost.") + + } catch { + print("💣 Failed to destroy broken CoreData database, delete the app.") + } + + print("💣💥 Unresolved error \(error), \(error.userInfo)") } }) } diff --git a/MeshtasticClient/Views/ContentView.swift b/MeshtasticClient/Views/ContentView.swift index db8610ae..d0ba3a04 100644 --- a/MeshtasticClient/Views/ContentView.swift +++ b/MeshtasticClient/Views/ContentView.swift @@ -19,21 +19,21 @@ struct ContentView: View { var body: some View { TabView(selection: $selection) { - Contacts() - .tabItem { - Label("Messages", systemImage: "text.bubble") - .symbolRenderingMode(.hierarchical) - .symbolVariant(.none) - - } - .tag(Tab.contacts) -// Channels() -// .tabItem { -// Label("Messages", systemImage: "text.bubble") +// Contacts() +// .tabItem { +// Label("Messages", systemImage: "text.bubble") // .symbolRenderingMode(.hierarchical) -// .symbolVariant(.none) -// } -// .tag(Tab.messages) +// .symbolVariant(.none) +// +// } +// .tag(Tab.contacts) + Channels() + .tabItem { + Label("Messages", systemImage: "text.bubble") + .symbolRenderingMode(.hierarchical) + .symbolVariant(.none) + } + .tag(Tab.messages) Connect() .tabItem { Label("Bluetooth", systemImage: "dot.radiowaves.left.and.right") diff --git a/MeshtasticClient/Views/Messages/Channels.swift b/MeshtasticClient/Views/Messages/Channels.swift index 8d2aa390..1d51c4d2 100644 --- a/MeshtasticClient/Views/Messages/Channels.swift +++ b/MeshtasticClient/Views/Messages/Channels.swift @@ -1,44 +1,44 @@ -//import Foundation -//import SwiftUI -//import CoreBluetooth -// -//struct Channels: View { -// -// @State private var isShowingDetailView = true -// -// var body: some View { -// -// NavigationView { -// -// NavigationLink(destination: Messages(), isActive: $isShowingDetailView) { -// -// List { -// -// HStack { -// -// Image(systemName: "dial.max.fill") -// .font(.system(size: 62)) -// .symbolRenderingMode(.hierarchical) -// .padding(.trailing) -// .foregroundColor(.accentColor) -// -// Text("Primary") -// .font(.largeTitle) -// -// }.padding() -// } -// } -// .navigationTitle("Channels") -// } -// .navigationViewStyle(DoubleColumnNavigationViewStyle()) -// } -//} -// -//struct MessageList_Previews: PreviewProvider { -// -// static var previews: some View { -// Group { -// Channels() -// } -// } -//} +import Foundation +import SwiftUI +import CoreBluetooth + +struct Channels: View { + + @State private var isShowingDetailView = true + + var body: some View { + + NavigationView { + + NavigationLink(destination: Messages(), isActive: $isShowingDetailView) { + + List { + + HStack { + + Image(systemName: "dial.max.fill") + .font(.system(size: 62)) + .symbolRenderingMode(.hierarchical) + .padding(.trailing) + .foregroundColor(.accentColor) + + Text("All - Broadcast") + .font(.largeTitle) + + }.padding() + } + } + .navigationTitle("Contacts") + } + .navigationViewStyle(DoubleColumnNavigationViewStyle()) + } +} + +struct MessageList_Previews: PreviewProvider { + + static var previews: some View { + Group { + Channels() + } + } +} diff --git a/MeshtasticClient/Views/Messages/Contacts.swift b/MeshtasticClient/Views/Messages/Contacts.swift index 8d898813..734fec19 100644 --- a/MeshtasticClient/Views/Messages/Contacts.swift +++ b/MeshtasticClient/Views/Messages/Contacts.swift @@ -1,141 +1,141 @@ +//// +//// Contacts.swift +//// MeshtasticClient +//// +//// Created by Garth Vander Houwen on 12/21/21. +//// // -// Contacts.swift -// MeshtasticClient +//import SwiftUI // -// Created by Garth Vander Houwen on 12/21/21. +//struct Contacts: View { // - -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 { - - NavigationView { - - List(users) { (user: UserEntity) in - - if user.receivedMessages?.count ?? 0 > 0 { - - let currentUserNum = self.bleManager.connectedPeripheral != nil ? self.bleManager.connectedPeripheral.num : 0 - - let mostRecentBC = user.receivedMessages?.array.last as! MessageEntity - - let mostRecentDM = user.receivedMessages?.array.last(where: {($0 as! MessageEntity).toUser!.num == currentUserNum }) as? MessageEntity - - let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64(mostRecentDM?.messageTimestamp ?? mostRecentBC.messageTimestamp))) - let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0 - let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0 - - if user.num != currentUserNum && (user.num == bleManager.broadcastNodeNum || mostRecentDM != nil) { //}|| user.num == mostRecent.toUser!.num { - - NavigationLink(destination: UserMessageList(user: user)) { - - HStack { - - VStack { - - CircleText(text: user.shortName ?? "???", color: Color.blue) - } - .padding([.leading, .trailing]) - - VStack { - - HStack { - - VStack { - - Text(user.longName ?? "Unknown").font(.headline).fixedSize() - } - - 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(mostRecentDM != nil ? mostRecentDM?.messagePayload as! String : (mostRecentBC.messagePayload ?? "Unknown" as! String)) - .frame(height: 60) - .truncationMode(.tail) - .foregroundColor(Color.gray) - .frame(maxWidth: .infinity, alignment: .leading) - } - }.padding(.top, 15) - } - } - } - - } else if self.bleManager.connectedPeripheral == nil || ((self.bleManager.connectedPeripheral != nil ? self.bleManager.connectedPeripheral.num : 0) != user.num) { - - NavigationLink(destination: UserMessageList(user: user)) { - - HStack { - - VStack { - - CircleText(text: user.shortName ?? "???", color: Color.blue) - } - .padding(.trailing) - - VStack { - - HStack { - - VStack { - - Text(user.longName ?? "Unknown").font(.headline).fixedSize() - } - - VStack { - Text(" ") - } - .frame(maxWidth: .infinity, alignment: .trailing) - } - .listRowSeparator(.hidden).frame(height: 5) - } - }.padding() - } - } - } - .navigationTitle("Contacts") - .navigationBarTitleDisplayMode(.inline) - } - .listStyle(PlainListStyle()) - } -} - -struct Contacts_Previews: PreviewProvider { - static var previews: some View { - Contacts() - } -} +// @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 { +// +// NavigationView { +// +// List(users) { (user: UserEntity) in +// +// if user.receivedMessages?.count ?? 0 > 0 { +// +// let currentUserNum = self.bleManager.connectedPeripheral != nil ? self.bleManager.connectedPeripheral.num : 0 +// +// let mostRecentBC = user.receivedMessages?.array.last as! MessageEntity +// +// let mostRecentDM = user.receivedMessages?.array.last(where: {($0 as! MessageEntity).toUser!.num == currentUserNum }) as? MessageEntity +// +// let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64(mostRecentDM?.messageTimestamp ?? mostRecentBC.messageTimestamp))) +// let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0 +// let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0 +// +// if user.num == bleManager.broadcastNodeNum {//user.num != currentUserNum && (user.num == bleManager.broadcastNodeNum || mostRecentDM != nil) { +// +// NavigationLink(destination: UserMessageList(user: user)) { +// +// HStack { +// +// VStack { +// +// CircleText(text: user.shortName ?? "???", color: Color.blue) +// } +// .padding([.leading, .trailing]) +// +// VStack { +// +// HStack { +// +// VStack { +// +// Text(user.longName ?? "Unknown").font(.headline).fixedSize() +// } +// +// 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(mostRecentDM != nil ? mostRecentDM?.messagePayload as! String : (mostRecentBC.messagePayload ?? "Unknown" )) +// .frame(height: 60) +// .truncationMode(.tail) +// .foregroundColor(Color.gray) +// .frame(maxWidth: .infinity, alignment: .leading) +// } +// }.padding(.top, 15) +// } +// } +// } +// +// } else if false {// self.bleManager.connectedPeripheral == nil || ((self.bleManager.connectedPeripheral != nil ? self.bleManager.connectedPeripheral.num : 0) != user.num) { +// +// NavigationLink(destination: UserMessageList(user: user)) { +// +// HStack { +// +// VStack { +// +// CircleText(text: user.shortName ?? "???", color: Color.blue) +// } +// .padding(.trailing) +// +// VStack { +// +// HStack { +// +// VStack { +// +// Text(user.longName ?? "Unknown").font(.headline).fixedSize() +// } +// +// VStack { +// Text(" ") +// } +// .frame(maxWidth: .infinity, alignment: .trailing) +// } +// .listRowSeparator(.hidden).frame(height: 5) +// } +// }.padding() +// } +// } +// } +// .navigationTitle("Contacts") +// .navigationBarTitleDisplayMode(.inline) +// } +// .listStyle(PlainListStyle()) +// } +//} +// +//struct Contacts_Previews: PreviewProvider { +// static var previews: some View { +// Contacts() +// } +//} diff --git a/MeshtasticClient/Views/Messages/UserMessageList.swift b/MeshtasticClient/Views/Messages/UserMessageList.swift index 1a264094..3162845a 100644 --- a/MeshtasticClient/Views/Messages/UserMessageList.swift +++ b/MeshtasticClient/Views/Messages/UserMessageList.swift @@ -1,202 +1,206 @@ +//// +//// UserMessageList.swift +//// MeshtasticClient +//// +//// Created by Garth Vander Houwen on 12/24/21. +//// // -// UserMessageList.swift -// MeshtasticClient +//import SwiftUI +//import CoreData // -// Created by Garth Vander Houwen on 12/24/21. +//struct UserMessageList: View { // - -import SwiftUI -import CoreData - -struct UserMessageList: View { - - @Environment(\.managedObjectContext) var context - @EnvironmentObject var bleManager: BLEManager - - enum Field: Hashable { - case messageText - } - // Keyboard State - @State var typingMessage: String = "" - @State private var totalBytes = 0 - var maxbytes = 228 - @State var lastTypingMessage = "" - @FocusState var focusedField: Field? - - var user: UserEntity - - @State var showDeleteMessageAlert = false - @State private var deleteMessageId: Int64 = 0 - - var body: some View { - - HStack { - - VStack { - - List { - - ScrollViewReader { _ in - - ScrollView { - - if user.receivedMessages?.count ?? 0 > 0 { - - ForEach( user.receivedMessages?.array as! [MessageEntity], id: \.self) { (message: MessageEntity) in - - HStack { - let currentUser: Bool = (bleManager.connectedPeripheral == nil) ? false : ((bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.num == message.fromUser?.num) ? true : false ) - - - if message.toUser!.num == Int64(bleManager.broadcastNodeNum) || ((bleManager.connectedPeripheral) != nil && bleManager.connectedPeripheral.num == message.fromUser?.num) ? true : true { - - - - VStack { - - HStack (alignment: .top) { - - CircleText(text: (message.fromUser?.shortName ?? "???"), 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 - - print(deleteMessageId) - }) - - VStack(alignment: .leading) { - - Text(message.messagePayload ?? "EMPTY MESSAGE") - .textSelection(.enabled) - .padding(10) - .foregroundColor(.white) - .background(currentUser ? Color.blue : Color(.darkGray)) - .cornerRadius(10) - - 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 { - Text("Unknown").font(.caption2).foregroundColor(.gray) - } - } - .padding(.bottom, 10) - } - Spacer() - } - } - - } - } - } - } - } - } - } - - HStack(alignment: .top) { - - ZStack { - - let kbType = UIKeyboardType(rawValue: UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0) - TextEditor(text: $typingMessage) - .onChange(of: typingMessage, perform: { value in - - let size = value.utf8.count - totalBytes = size - if totalBytes <= maxbytes { - // Allow the user to type - lastTypingMessage = typingMessage - } else { - // Set the message back and remove the bytes over the count - self.typingMessage = lastTypingMessage - } - }) - .keyboardType(kbType!) - .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) - .font(.subheadline) - .accentColor(.accentColor) - } - } - .padding(.horizontal, 8) - .focused($focusedField, equals: .messageText) - .multilineTextAlignment(.leading) - .frame(minHeight: 100, maxHeight: 160) - - 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, toUserNum: user.num) { - typingMessage = "" - focusedField = nil - } else { - - _ = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (_) in - - if bleManager.sendMessage(message: typingMessage, toUserNum: user.num) { - typingMessage = "" - } - } - } - - }) { - Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.blue) - } - - } - .padding(.all, 15) - } - } - .navigationViewStyle(.stack) - .navigationBarTitleDisplayMode(.inline) - .toolbar { - ToolbarItem(placement: .principal) { - - HStack { - - CircleText(text: user.shortName ?? "???", color: .blue).fixedSize() - Text(user.longName ?? "Unknown").foregroundColor(.gray).font(.caption2).fixedSize() - } - } - ToolbarItem(placement: .navigationBarTrailing) { - ZStack { - - ConnectedDevice( - bluetoothOn: bleManager.isSwitchedOn, - deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") - } - } - } - .onAppear(perform: { - - self.bleManager.context = context - - }) - } - -} +// @Environment(\.managedObjectContext) var context +// @EnvironmentObject var bleManager: BLEManager +// +// enum Field: Hashable { +// case messageText +// } +// // Keyboard State +// @State var typingMessage: String = "" +// @State private var totalBytes = 0 +// var maxbytes = 228 +// @State var lastTypingMessage = "" +// @FocusState var focusedField: Field? +// +// var user: UserEntity +// +// @State var showDeleteMessageAlert = false +// @State private var deleteMessageId: Int64 = 0 +// +// var body: some View { +// +//// HStack { +// +// VStack { +// +// // List { +// +// ScrollViewReader { _ in +// +// ScrollView { +// +// if user.receivedMessages?.count ?? 0 > 0 { +// +// ForEach( user.receivedMessages?.array as! [MessageEntity], id: \.self) { (message: MessageEntity) in +// +// // HStack { +// let currentUser: Bool = (bleManager.connectedPeripheral == nil) ? false : ((bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.num == message.fromUser?.num) ? true : false ) +// +// +// if message.toUser!.num == Int64(bleManager.broadcastNodeNum) || ((bleManager.connectedPeripheral) != nil && bleManager.connectedPeripheral.num == message.fromUser?.num) ? true : true { +// +// +// HStack (alignment: .top) { +// +// if currentUser { Spacer(minLength:50) } +// +// if !currentUser { +// +// CircleText(text: (message.fromUser?.shortName ?? "???"), 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 +// print(deleteMessageId) +// }) +// } +// +// VStack(alignment: currentUser ? .trailing : .leading) { +// +// Text(message.messagePayload ?? "EMPTY MESSAGE") +// .textSelection(.enabled) +// .padding(10) +// .foregroundColor(.white) +// .background(currentUser ? Color.blue : Color(.darkGray)) +// .cornerRadius(15) +// +// 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 { +// Text("Unknown").font(.caption2).foregroundColor(.gray) +// } +// } +// .padding(.bottom, 10) +// } +// if !currentUser { +// Spacer(minLength:50) +// } +// } +// .padding(.trailing) +// .frame(maxWidth: .infinity) +// } +// // } +// } +// .listRowSeparator(.hidden) +// } +// } +// } +// // } +// // .padding(.top) +// +// HStack(alignment: .top) { +// +// ZStack { +// +// let kbType = UIKeyboardType(rawValue: UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0) +// TextEditor(text: $typingMessage) +// .onChange(of: typingMessage, perform: { value in +// +// let size = value.utf8.count +// totalBytes = size +// if totalBytes <= maxbytes { +// // Allow the user to type +// lastTypingMessage = typingMessage +// } else { +// // Set the message back and remove the bytes over the count +// self.typingMessage = lastTypingMessage +// } +// }) +// .keyboardType(kbType!) +// .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) +// .font(.subheadline) +// .accentColor(.accentColor) +// } +// } +// .padding(.horizontal, 8) +// .focused($focusedField, equals: .messageText) +// .multilineTextAlignment(.leading) +// .frame(minHeight: 100, maxHeight: 160) +// +// 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, toUserNum: user.num) { +// typingMessage = "" +// focusedField = nil +// } else { +// +// _ = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (_) in +// +// if bleManager.sendMessage(message: typingMessage, toUserNum: user.num) { +// typingMessage = "" +// } +// } +// } +// +// }) { +// Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.blue) +// } +// +// } +// .padding(.all, 15) +// } +//// } +// .navigationViewStyle(.stack) +// .navigationBarTitleDisplayMode(.inline) +// .toolbar { +// ToolbarItem(placement: .principal) { +// +// HStack { +// +// CircleText(text: user.shortName ?? "???", color: .blue).fixedSize() +// Text(user.longName ?? "Unknown").foregroundColor(.gray).font(.caption2).fixedSize() +// } +// } +// ToolbarItem(placement: .navigationBarTrailing) { +// ZStack { +// +// ConnectedDevice( +// bluetoothOn: bleManager.isSwitchedOn, +// deviceConnected: bleManager.connectedPeripheral != nil, +// name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") +// } +// } +// } +// .onAppear(perform: { +// +// self.bleManager.context = context +// +// }) +// } +// +//} diff --git a/MeshtasticClient/Views/Nodes/NodeDetail.swift b/MeshtasticClient/Views/Nodes/NodeDetail.swift index 6b6cb28f..90374520 100644 --- a/MeshtasticClient/Views/Nodes/NodeDetail.swift +++ b/MeshtasticClient/Views/Nodes/NodeDetail.swift @@ -175,7 +175,11 @@ struct NodeDetail: View { } Text(String(node.num)).font(.title3).foregroundColor(.gray) } - }.padding() + }.padding(5) + HStack { + Text("MAC Address: ") + Text(String(node.user?.macaddr?.macAddressString ?? "not a valid mac address")).foregroundColor(.gray) + } if node.positions?.count ?? 0 > 1 {