From 49e19a4a765fd48850450dcbd8d7b0edbe899fa7 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 17 Oct 2021 01:05:44 -0700 Subject: [PATCH] V 1.25.9 Add Settings and move nav around. Configure project for MacOS TestFlight --- Meshtastic Client.xcodeproj/project.pbxproj | 13 +-- MeshtasticClient/Model/MeshData.swift | 9 ++ MeshtasticClient/Views/ContentView.swift | 25 +++--- .../Views/Messages/Channels.swift | 4 +- .../Views/Messages/Messages.swift | 14 +-- MeshtasticClient/Views/Nodes/NodeList.swift | 1 + .../Views/Settings/AppSettings.swift | 90 +++++++++++++++++-- 7 files changed, 125 insertions(+), 31 deletions(-) diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index f3a834f3..31ab48b6 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -202,6 +202,7 @@ DD8EDE9226F97A2B00A5A10B /* Frameworks */, ); sourceTree = ""; + usesTabs = 1; }; DDC2E15526CE248E0042C5E4 /* Products */ = { isa = PBXGroup; @@ -659,11 +660,11 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.25.7; + MARKETING_VERSION = 1.25.9; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -686,11 +687,11 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.25.7; + MARKETING_VERSION = 1.25.9; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/MeshtasticClient/Model/MeshData.swift b/MeshtasticClient/Model/MeshData.swift index 4ccaa186..25c65bc6 100644 --- a/MeshtasticClient/Model/MeshData.swift +++ b/MeshtasticClient/Model/MeshData.swift @@ -29,6 +29,15 @@ class MeshData: ObservableObject { return } guard let nodeList = try? JSONDecoder().decode([NodeInfoModel].self, from: data) else { + do { + // If the file is borked delete it so we stop crashing + try FileManager.default.removeItem(at: Self.fileURL) + } + catch { + + fatalError("Can't delete saved node data.") + } + fatalError("Can't decode saved node data.") } DispatchQueue.main.async { diff --git a/MeshtasticClient/Views/ContentView.swift b/MeshtasticClient/Views/ContentView.swift index 76dfb16c..84cbd0b3 100644 --- a/MeshtasticClient/Views/ContentView.swift +++ b/MeshtasticClient/Views/ContentView.swift @@ -21,33 +21,38 @@ struct ContentView: View { Channels() .tabItem { Label("Messages", systemImage: "text.bubble") + .symbolRenderingMode(.hierarchical) .symbolVariant(.none) } .tag(Tab.messages) + Connect() + .tabItem { + Label("Bluetooth", systemImage: "dot.radiowaves.left.and.right") + .symbolRenderingMode(.hierarchical) + .symbolVariant(.none) + } + .tag(Tab.ble) NodeList() .tabItem { Label("Nodes", systemImage: "flipphone") + .symbolRenderingMode(.hierarchical) .symbolVariant(.none) } .tag(Tab.nodes) NodeMap() .tabItem { Label("Mesh Map", systemImage: "map") + .symbolRenderingMode(.hierarchical) .symbolVariant(.none) } .tag(Tab.map) - Connect() + AppSettings() .tabItem { - Label("Bluetooth", systemImage: "dot.radiowaves.left.and.right") - .symbolVariant(.none) + Label("Settings", systemImage: "gear") + .symbolRenderingMode(.hierarchical) + .symbolVariant(.none) } - .tag(Tab.ble) - //AppSettings() - // .tabItem { - // Label("Settings", systemImage: "gear") - // .symbolRenderingMode(.hierarchical) - // } - // .tag(Tab.settings) + .tag(Tab.settings) } } } diff --git a/MeshtasticClient/Views/Messages/Channels.swift b/MeshtasticClient/Views/Messages/Channels.swift index 1675e3e7..d14c2ca5 100644 --- a/MeshtasticClient/Views/Messages/Channels.swift +++ b/MeshtasticClient/Views/Messages/Channels.swift @@ -3,6 +3,7 @@ import SwiftUI import CoreBluetooth struct Channels: View { + // Message Data and Bluetooth @EnvironmentObject var messageData: MessageData @EnvironmentObject var bleManager: BLEManager @@ -33,11 +34,12 @@ struct Channels: View { } .navigationTitle("Channels") } - .navigationViewStyle(StackNavigationViewStyle()) + .navigationViewStyle(DoubleColumnNavigationViewStyle()) } } struct MessageList_Previews: PreviewProvider { + static let meshData = MeshData() static var previews: some View { diff --git a/MeshtasticClient/Views/Messages/Messages.swift b/MeshtasticClient/Views/Messages/Messages.swift index c9eca918..08313a4d 100644 --- a/MeshtasticClient/Views/Messages/Messages.swift +++ b/MeshtasticClient/Views/Messages/Messages.swift @@ -1,5 +1,6 @@ import SwiftUI import MapKit +import Foundation import CoreLocation struct Messages: View { @@ -8,8 +9,11 @@ struct Messages: View { case messageText } + @ObservedObject var userSettings = UserSettings() + + // Keyboard State - @State var typingMessage: String = "" + @State var typingMessage: String = "" @State private var totalBytes = 0 @State private var lastTypingMessage = "" @FocusState private var focusedField: Field? @@ -43,7 +47,6 @@ struct Messages: View { MessageBubble(contentMessage: message.messagePayload, isCurrentUser: currentUser, time: Int32(message.messageTimestamp), shortName: message.fromUserShortName) } .onAppear(perform: { scrollView.scrollTo(bottomId) } ) - Text("Hidden Bottom Anchor").hidden().frame(height: 0).id(bottomId) } .onReceive(timer) { input in @@ -59,8 +62,9 @@ struct Messages: View { HStack (alignment: .top) { ZStack { - - TextEditor(text: $typingMessage) + //let kbType = Enum.Parse(typeof(KeyboardType), userSettings.keyboardType, true); + let kbType = UIKeyboardType(rawValue: userSettings.keyboardType) + TextEditor(text: $typingMessage) .onChange(of: typingMessage, perform: { value in let size = value.utf8.count @@ -74,7 +78,7 @@ struct Messages: View { self.typingMessage = lastTypingMessage } }) - .keyboardType(.default) + .keyboardType(kbType!) .toolbar { ToolbarItemGroup(placement: .keyboard) { diff --git a/MeshtasticClient/Views/Nodes/NodeList.swift b/MeshtasticClient/Views/Nodes/NodeList.swift index ca4339b9..2e2f77c6 100644 --- a/MeshtasticClient/Views/Nodes/NodeList.swift +++ b/MeshtasticClient/Views/Nodes/NodeList.swift @@ -77,6 +77,7 @@ struct NodeList: View { .navigationTitle("All Nodes") } .ignoresSafeArea(.all, edges: [.leading, .trailing]) + .navigationViewStyle(DoubleColumnNavigationViewStyle()) .onAppear{ meshData.load() } diff --git a/MeshtasticClient/Views/Settings/AppSettings.swift b/MeshtasticClient/Views/Settings/AppSettings.swift index 5dad31c6..85716149 100644 --- a/MeshtasticClient/Views/Settings/AppSettings.swift +++ b/MeshtasticClient/Views/Settings/AppSettings.swift @@ -1,23 +1,95 @@ import Foundation +import Combine 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" + } + } + } +} + +class UserSettings: ObservableObject { + @Published var username: String { + didSet { + UserDefaults.standard.set(username, forKey: "username") + } + } + @Published var provideLocation: Bool { + didSet { + UserDefaults.standard.set(provideLocation, forKey: "provideLocation") + } + } + @Published var keyboardType: Int { + didSet { + UserDefaults.standard.set(keyboardType, forKey: "keyboardType") + } + } + + init() { + self.username = UserDefaults.standard.object(forKey: "username") as? String ?? "" + self.provideLocation = UserDefaults.standard.object(forKey: "provideLocation") as? Bool ?? false + self.keyboardType = UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0 + } +} struct AppSettings: View { - + + @ObservedObject var userSettings = UserSettings() + var body: some View { NavigationView { GeometryReader { bounds in - NavigationLink(destination: Messages()) { - - List{ - - } - } - } + Form { + Section(header: Text("USER DETAILS")) { + HStack{ + + Text("User Name") + TextField("Username", text: $userSettings.username) + .foregroundColor(.gray) + } + Toggle(isOn: $userSettings.provideLocation) { + + Text("Provide location to mesh") + } + } + Section(header: Text("MESSAGING OPTIONS")) { + + Picker("Keyboard Type", selection: $userSettings.keyboardType) { + ForEach(KeyboardType.allCases) { kb in + Text(kb.description) + } + } + .pickerStyle(DefaultPickerStyle()) + } + } + } .navigationTitle("App Settings") } - } + .navigationViewStyle(StackNavigationViewStyle()) } } struct AppSettings_Previews: PreviewProvider {