diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 99f6dd10..37f31711 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -2268,41 +2268,6 @@ } } }, - "Admin & Direct Message Keys" : { - "extractionState" : "stale", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Schlüssel für Administrator und Direktnachrichten" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Tasti amministratore e messaggi diretti" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Админ и кључеви директних порука" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理员 & 私信密钥" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "管理與直接訊息加密金鑰" - } - } - } - }, "Admin Keys" : { }, @@ -4366,33 +4331,8 @@ } } }, - "BLE RSSI: %lld" : { - "localizations" : { - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "RSSI BLE: %lld" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "BLE RSSI: %lld" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "BLE RSSI: %lld" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "藍牙訊號強度(RSSI):%lld" - } - } - } + "BLE RSSI %lld" : { + }, "BLE: %@" : { "localizations" : { @@ -11809,6 +11749,9 @@ } } } + }, + "Favorited and ignored nodes are always retained. Nodes without PKC keys are cleared from the app database on the schedule set by the user, nodes with PKC keys are cleared only if the interval is set to 7 days or longer. This feature only purges nodes from the app that are not stored in the device node database." : { + }, "Favorites" : { "localizations" : { @@ -16247,40 +16190,6 @@ } } }, - "Long Name: %@" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Langer Name: %@" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nome lungo: %@" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Дуго име: %@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "长名称: %@" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "完整名稱:%@" - } - } - } - }, "Long press to favorite or mute the contact or delete a conversation." : { "localizations" : { "it" : { @@ -19830,9 +19739,6 @@ } } } - }, - "Nodes without PKI keys are cleared from the app database on the schedule set by the user, nodes with PKI keys are cleared only if the interval is set to 7 days or longer. This feature only purges nodes from the app that are not stored in the device node database." : { - }, "None" : { "localizations" : { @@ -20046,34 +19952,6 @@ } } }, - "Num: %@" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Anzahl: %@" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Num: %@" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Број: %@" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "Num: %@" - } - } - } - }, "Number of hops" : { "localizations" : { "de" : { @@ -27289,35 +27167,6 @@ } } }, - "Sent out to other nodes on the mesh to allow them to compute a shared secret key." : { - "extractionState" : "stale", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Wird an andere Knoten im Netz gesendet, damit diese einen gemeinsamen geheimen Schlüssel berechnen können." - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Inviato agli altri nodi della rete per consentire loro di calcolare una chiave segreta condivisa." - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Послато другим чворовима на меш мрежи како би им омогућило да израчунају заједнички тајни кључ." - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "傳送到網路上的其他節點,以便共同計算一組共享私鑰。" - } - } - } - }, "Sequence number" : { "localizations" : { "de" : { @@ -28154,40 +28003,6 @@ } } }, - "Short Name: %@" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Kurzname: %@" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nome breve: %@" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Кратко име: %@" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "短名称: %@" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "簡短名稱:%@" - } - } - } - }, "Short Range - Fast" : { "localizations" : { "it" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 883f3571..07cc1fb3 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -100,6 +100,7 @@ DD1BEF4A2E0292320090CE24 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BEF492E0292220090CE24 /* KeychainHelper.swift */; }; DD1BEF4C2E030D310090CE24 /* KeyBackupStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BEF4B2E030D240090CE24 /* KeyBackupStatus.swift */; }; DD1BEF4E2E03916A0090CE24 /* ChannelsHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BEF4D2E0391620090CE24 /* ChannelsHelp.swift */; }; + DD1BEF502E0528AA0090CE24 /* PersistantTips.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BEF4F2E0528A80090CE24 /* PersistantTips.swift */; }; DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */; }; DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2160AE28C5552500C17253 /* MQTTConfig.swift */; }; DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */; }; @@ -378,6 +379,7 @@ DD1BEF492E0292220090CE24 /* KeychainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainHelper.swift; sourceTree = ""; }; DD1BEF4B2E030D240090CE24 /* KeyBackupStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupStatus.swift; sourceTree = ""; }; DD1BEF4D2E0391620090CE24 /* ChannelsHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsHelp.swift; sourceTree = ""; }; + DD1BEF4F2E0528A80090CE24 /* PersistantTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistantTips.swift; sourceTree = ""; }; DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserMessageList.swift; sourceTree = ""; }; DD2160AE28C5552500C17253 /* MQTTConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTConfig.swift; sourceTree = ""; }; DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = ""; }; @@ -863,6 +865,7 @@ DD7709392AA1ABA1007A8BF0 /* Tips */ = { isa = PBXGroup; children = ( + DD1BEF4F2E0528A80090CE24 /* PersistantTips.swift */, DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */, DD77093C2AA1AFA3007A8BF0 /* ChannelTips.swift */, DDC1B8192AB5377B00C71E39 /* MessagesTips.swift */, @@ -1439,6 +1442,7 @@ 25F5D5BE2C3F6D87008036E3 /* NavigationState.swift in Sources */, 2373AE152D0A24930086C749 /* MetricsSeriesList.swift in Sources */, DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */, + DD1BEF502E0528AA0090CE24 /* PersistantTips.swift in Sources */, DDDB445429F8AD1600EE2349 /* Data.swift in Sources */, DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */, DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */, diff --git a/Meshtastic/MeshtasticApp.swift b/Meshtastic/MeshtasticApp.swift index 9a0e9165..1512cae2 100644 --- a/Meshtastic/MeshtasticApp.swift +++ b/Meshtastic/MeshtasticApp.swift @@ -28,17 +28,16 @@ struct MeshtasticAppleApp: App { router: Router() ) self._appState = ObservedObject(wrappedValue: appState) - // Initialize the BLEManager singleton with the necessary dependencies BLEManager.setup(appState: appState, context: persistenceController.container.viewContext) self.persistenceController = persistenceController - // Wire up router self.appDelegate.router = appState.router - // Show Tips + #if DEBUG + // Show tips in development try? Tips.resetDatastore() + #endif } - var body: some Scene { WindowGroup { ContentView( diff --git a/Meshtastic/Tips/PersistantTips.swift b/Meshtastic/Tips/PersistantTips.swift new file mode 100644 index 00000000..24093285 --- /dev/null +++ b/Meshtastic/Tips/PersistantTips.swift @@ -0,0 +1,37 @@ +// +// Untitled.swift +// Meshtastic +// +// Created by Garth Vander Houwen on 6/19/25. +// +import TipKit + +struct PersistentTip: TipViewStyle { + func makeBody(configuration: Configuration) -> some View { + VStack { + HStack(alignment: .top) { + if let image = configuration.image { + image + .font(.system(size: 42)) + .foregroundColor(.accentColor) + .padding(.trailing, 5) + } + VStack(alignment: .leading) { + if let title = configuration.title { + title + .bold() + .font(.headline) + } + if let message = configuration.message { + message + .foregroundStyle(.secondary) + .font(.callout) + } + } + } + } + .frame(maxWidth: .infinity) + .backgroundStyle(.thinMaterial) + .padding(.top, 5) + } +} diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 1176241a..53e27ae6 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -46,9 +46,10 @@ struct Connect: View { VStack { List { if bleManager.isSwitchedOn { - Section(header: Text("Connected Radio").font(.title)) { + Section { if let connectedPeripheral = bleManager.connectedPeripheral, connectedPeripheral.peripheral.state == .connected { TipView(BluetoothConnectionTip(), arrowEdge: .bottom) + .tipViewStyle(PersistentTip()) VStack(alignment: .leading) { HStack { VStack(alignment: .center) { @@ -104,6 +105,8 @@ struct Connect: View { .contextMenu { if node != nil { + Label("\(String(node!.num))", systemImage: "number") + Label("BLE RSSI \(connectedPeripheral.rssi)", systemImage: "cellularbars") #if !targetEnvironment(macCatalyst) if bleManager.isSubscribed { Button { @@ -123,10 +126,6 @@ struct Connect: View { } } #endif - Text("Num: \(String(node!.num))") - Text("Short Name: \(node?.user?.shortName ?? "?")") - Text("Long Name: \(node?.user?.longName?.addingVariationSelectors ?? "Unknown".localized)") - Text("BLE RSSI: \(connectedPeripheral.rssi)") if bleManager.allowDisconnect { Button(role: .destructive) { if let connectedPeripheral = bleManager.connectedPeripheral, @@ -136,7 +135,7 @@ struct Connect: View { } label: { Label("Disconnect", systemImage: "antenna.radiowaves.left.and.right.slash") } - Button { + Button(role: .destructive) { if !bleManager.sendShutdown(fromUser: node!.user!, toUser: node!.user!) { Logger.mesh.error("Shutdown Failed") } diff --git a/Meshtastic/Views/Messages/Messages.swift b/Meshtastic/Views/Messages/Messages.swift index cb6947c0..8a75faf7 100644 --- a/Meshtastic/Views/Messages/Messages.swift +++ b/Meshtastic/Views/Messages/Messages.swift @@ -64,6 +64,7 @@ struct Messages: View { } TipView(MessagesTip(), arrowEdge: .top) + .tipViewStyle(PersistentTip()) } .navigationTitle("Messages") .navigationBarTitleDisplayMode(.large) diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index 7bf044e6..93d1e8da 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -72,7 +72,7 @@ struct AppSettings: View { Text("180") } } - Text("Nodes without PKI keys are cleared from the app database on the schedule set by the user, nodes with PKI keys are cleared only if the interval is set to 7 days or longer. This feature only purges nodes from the app that are not stored in the device node database.") + Text("Favorited and ignored nodes are always retained. Nodes without PKC keys are cleared from the app database on the schedule set by the user, nodes with PKC keys are cleared only if the interval is set to 7 days or longer. This feature only purges nodes from the app that are not stored in the device node database.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index a4b664b9..426d95e9 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -440,6 +440,7 @@ struct Settings: View { } } TipView(AdminChannelTip(), arrowEdge: .top) + .tipViewStyle(PersistentTip()) } else { if bleManager.connectedPeripheral != nil { Text("Connected Node \(node?.user?.longName?.addingVariationSelectors ?? "Unknown".localized)")