From d7ad7a7e7278fc096e900d6dd1f93304bd64f933 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 19 Jun 2025 23:17:40 -0700 Subject: [PATCH] Persistent Tip style for bluetooth, messages and administration --- Localizable.xcstrings | 6 ++-- Meshtastic.xcodeproj/project.pbxproj | 4 +++ Meshtastic/MeshtasticApp.swift | 7 ++--- Meshtastic/Tips/PersistantTips.swift | 37 ++++++++++++++++++++++++ Meshtastic/Views/Bluetooth/Connect.swift | 3 +- Meshtastic/Views/Messages/Messages.swift | 1 + Meshtastic/Views/Settings/Settings.swift | 1 + 7 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 Meshtastic/Tips/PersistantTips.swift diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 99f6dd10..e5553909 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -11809,6 +11809,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" : { @@ -19830,9 +19833,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" : { 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..37ca7966 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) { 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/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)")