From aab23ef2d3478375821d6571fc12551dbccbfce9 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 19 Jul 2025 23:25:43 -0700 Subject: [PATCH] Update display config --- Localizable.xcstrings | 15 + Meshtastic.xcodeproj/project.pbxproj | 4 +- Meshtastic/Enums/DisplayEnums.swift | 2 +- Meshtastic/Enums/PositionConfigEnums.swift | 46 -- .../Meshtastic.xcdatamodeld/.xccurrentversion | 2 +- .../contents | 505 ++++++++++++++++++ Meshtastic/Persistence/UpdateCoreData.swift | 5 +- .../Views/Settings/Config/DisplayConfig.swift | 115 ++-- 8 files changed, 582 insertions(+), 112 deletions(-) create mode 100644 Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 54.xcdatamodel/contents diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 4fff08b0..350a36ac 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -9557,6 +9557,7 @@ } }, "Decimal Degrees Format" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -9719,6 +9720,7 @@ } }, "Degrees Minutes Seconds" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -16362,6 +16364,7 @@ } }, "GPS Format" : { + "extractionState" : "stale", "localizations" : { "it" : { "stringUnit" : { @@ -21356,6 +21359,7 @@ } }, "Military Grid Reference System" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -24772,6 +24776,7 @@ } }, "Open Location Code (aka Plus Codes)" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -25094,6 +25099,7 @@ } }, "Ordnance Survey Grid Reference" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -25460,6 +25466,9 @@ } } } + }, + "Override default screen layout." : { + }, "Pairing Mode" : { "localizations" : { @@ -36246,6 +36255,7 @@ } }, "The format used to display GPS coordinates on the device screen." : { + "extractionState" : "stale", "localizations" : { "it" : { "stringUnit" : { @@ -37801,8 +37811,12 @@ } } } + }, + "Timing" : { + }, "Timing & Format" : { + "extractionState" : "stale", "localizations" : { "it" : { "stringUnit" : { @@ -39029,6 +39043,7 @@ } }, "Universal Transverse Mercator" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index e5290176..988cb570 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -568,6 +568,7 @@ DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshActivityAttributes.swift; sourceTree = ""; }; DDDE5A1229AFEAB900490C6C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DDDEE5E229DBE43E00A8E078 /* MeshtasticDataModelV11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV11.xcdatamodel; sourceTree = ""; }; + DDDF34392E2CB8E600356DC3 /* MeshtasticDataModelV 54.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 54.xcdatamodel"; sourceTree = ""; }; DDDFE73E2D0D48FF0044463C /* IgnoreNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoreNodeButton.swift; sourceTree = ""; }; DDDFE7402D0D4A070044463C /* MeshtasticDataModelV 47.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 47.xcdatamodel"; sourceTree = ""; }; DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsEnums.swift; sourceTree = ""; }; @@ -2091,6 +2092,7 @@ DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DDDF34392E2CB8E600356DC3 /* MeshtasticDataModelV 54.xcdatamodel */, DD1BEF462DFF284C0090CE24 /* MeshtasticDataModelV 53.xcdatamodel */, DD0836AB2DE7C7CB00A3A973 /* MeshtasticDataModelV 52.xcdatamodel */, DD63CB4E2DD4FBEA00AFCAE2 /* MeshtasticDataModelV 51.xcdatamodel */, @@ -2145,7 +2147,7 @@ DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */, DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */, ); - currentVersion = DD1BEF462DFF284C0090CE24 /* MeshtasticDataModelV 53.xcdatamodel */; + currentVersion = DDDF34392E2CB8E600356DC3 /* MeshtasticDataModelV 54.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Enums/DisplayEnums.swift b/Meshtastic/Enums/DisplayEnums.swift index 664d72a5..44a1cd6e 100644 --- a/Meshtastic/Enums/DisplayEnums.swift +++ b/Meshtastic/Enums/DisplayEnums.swift @@ -85,7 +85,7 @@ enum ScreenCarouselIntervals: Int, CaseIterable, Identifiable { var description: String { switch self { case .off: - return "off".localized + return "off".localized.capitalized case .fifteenSeconds: return "Fifteen Seconds".localized case .thirtySeconds: diff --git a/Meshtastic/Enums/PositionConfigEnums.swift b/Meshtastic/Enums/PositionConfigEnums.swift index 24607df3..895dcda9 100644 --- a/Meshtastic/Enums/PositionConfigEnums.swift +++ b/Meshtastic/Enums/PositionConfigEnums.swift @@ -8,52 +8,6 @@ import Foundation import MeshtasticProtobufs -enum GpsFormats: Int, CaseIterable, Identifiable { - - case gpsFormatDec = 0 - case gpsFormatDms = 1 - case gpsFormatUtm = 2 - case gpsFormatMgrs = 3 - case gpsFormatOlc = 4 - case gpsFormatOsgr = 5 - - var id: Int { self.rawValue } - var description: String { - switch self { - case .gpsFormatDec: - return "Decimal Degrees Format".localized - case .gpsFormatDms: - return "Degrees Minutes Seconds".localized - case .gpsFormatUtm: - return "Universal Transverse Mercator".localized - case .gpsFormatMgrs: - return "Military Grid Reference System".localized - case .gpsFormatOlc: - return "Open Location Code (aka Plus Codes)".localized - case .gpsFormatOsgr: - return "Ordnance Survey Grid Reference".localized - } - } - func protoEnumValue() -> Config.DisplayConfig.GpsCoordinateFormat { - - switch self { - - case .gpsFormatDec: - return Config.DisplayConfig.GpsCoordinateFormat.dec - case .gpsFormatDms: - return Config.DisplayConfig.GpsCoordinateFormat.dms - case .gpsFormatUtm: - return Config.DisplayConfig.GpsCoordinateFormat.utm - case .gpsFormatMgrs: - return Config.DisplayConfig.GpsCoordinateFormat.mgrs - case .gpsFormatOlc: - return Config.DisplayConfig.GpsCoordinateFormat.olc - case .gpsFormatOsgr: - return Config.DisplayConfig.GpsCoordinateFormat.osgr - } - } -} - enum GpsUpdateIntervals: Int, CaseIterable, Identifiable { case thirtySeconds = 30 diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 057ab601..b6bc8ca5 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModelV 53.xcdatamodel + MeshtasticDataModelV 54.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 54.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 54.xcdatamodel/contents new file mode 100644 index 00000000..d89e9a0d --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 54.xcdatamodel/contents @@ -0,0 +1,505 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 3c762a49..b69c8442 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -610,7 +610,6 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses if fetchedNode[0].displayConfig == nil { let newDisplayConfig = DisplayConfigEntity(context: context) - newDisplayConfig.gpsFormat = Int32(config.gpsFormat.rawValue) newDisplayConfig.screenOnSeconds = Int32(truncatingIfNeeded: config.screenOnSecs) newDisplayConfig.screenCarouselInterval = Int32(truncatingIfNeeded: config.autoScreenCarouselSecs) newDisplayConfig.compassNorthTop = config.compassNorthTop @@ -622,8 +621,6 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses newDisplayConfig.use12HClock = config.use12HClock fetchedNode[0].displayConfig = newDisplayConfig } else { - - fetchedNode[0].displayConfig?.gpsFormat = Int32(config.gpsFormat.rawValue) fetchedNode[0].displayConfig?.screenOnSeconds = Int32(truncatingIfNeeded: config.screenOnSecs) fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(truncatingIfNeeded: config.autoScreenCarouselSecs) fetchedNode[0].displayConfig?.compassNorthTop = config.compassNorthTop @@ -631,8 +628,8 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses fetchedNode[0].displayConfig?.oledType = Int32(config.oled.rawValue) fetchedNode[0].displayConfig?.displayMode = Int32(config.displaymode.rawValue) fetchedNode[0].displayConfig?.units = Int32(config.units.rawValue) - fetchedNode[0].displayConfig?.use12HClock = config.use12HClock fetchedNode[0].displayConfig?.headingBold = config.headingBold + fetchedNode[0].displayConfig?.use12HClock = config.use12HClock } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 682bfd45..2a1a7c78 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -28,60 +28,44 @@ struct DisplayConfig: View { @State var displayMode = 0 @State var units = 0 @State var use12HourClock = false + @State var headingBold = false var body: some View { Form { ConfigHeader(title: "Display", config: \.displayConfig, node: node, onAppear: setDisplayValues) Section(header: Text("Device Screen")) { - VStack(alignment: .leading) { - Picker("Display Mode", selection: $displayMode ) { - ForEach(DisplayModes.allCases) { dm in - Text(dm.description) - } - } - Text("Override automatic OLED screen detection.") - .foregroundColor(.gray) - .font(.callout) - } - .pickerStyle(DefaultPickerStyle()) Toggle(isOn: $compassNorthTop) { Label("Always point north", systemImage: "location.north.circle") Text("The compass heading on the screen outside of the circle will always point north.") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - Toggle(isOn: $wakeOnTapOrMotion) { - Label("Wake Screen on tap or motion", systemImage: "gyroscope") - Text("Requires that there be an accelerometer on your device.") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - Toggle(isOn: $flipScreen) { - Label("Flip Screen", systemImage: "pip.swap") - Text("Flip screen vertically") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - VStack(alignment: .leading) { - Picker("OLED Type", selection: $oledType ) { - ForEach(OledTypes.allCases) { ot in - Text(ot.description) - } - } - Text("Override automatic OLED screen detection.") - .foregroundColor(.gray) - .font(.callout) - } - .pickerStyle(DefaultPickerStyle()) Toggle(isOn: $use12HourClock) { Label("12 Hour Clock", systemImage: "clock") Text("Sets the screen clock format to 12-hour.") } .tint(Color.accentColor) + + Toggle(isOn: $headingBold) { + Label("Bold Heading", systemImage: "bold") + Text("Bold the heading text on the screen.") + } + .tint(Color.accentColor) + VStack(alignment: .leading) { + Picker("Display Units", selection: $units ) { + ForEach(Units.allCases) { un in + Text(un.description) + } + } + Text("Units displayed on the device screen") + .foregroundColor(.gray) + .font(.callout) + } + .pickerStyle(DefaultPickerStyle()) } - Section(header: Text("Timing & Format")) { + Section(header: Text("Timing and Overrides")) { VStack(alignment: .leading) { Picker("Screen on for", selection: $screenOnSeconds ) { ForEach(ScreenOnIntervals.allCases) { soi in @@ -107,25 +91,36 @@ struct DisplayConfig: View { } .pickerStyle(DefaultPickerStyle()) + Toggle(isOn: $wakeOnTapOrMotion) { + Label("Wake Screen on tap or motion", systemImage: "gyroscope") + Text("Requires that there be an accelerometer on your device.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Toggle(isOn: $flipScreen) { + Label("Flip Screen", systemImage: "pip.swap") + Text("Flip screen vertically") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + VStack(alignment: .leading) { - Picker("GPS Format", selection: $gpsFormat ) { - ForEach(GpsFormats.allCases) { lu in - Text(lu.description) + Picker("Display Mode", selection: $displayMode ) { + ForEach(DisplayModes.allCases) { dm in + Text(dm.description) } } - Text("The format used to display GPS coordinates on the device screen.") + Text("Override default screen layout.") .foregroundColor(.gray) .font(.callout) } .pickerStyle(DefaultPickerStyle()) - VStack(alignment: .leading) { - Picker("Display Units", selection: $units ) { - ForEach(Units.allCases) { un in - Text(un.description) + Picker("OLED Type", selection: $oledType ) { + ForEach(OledTypes.allCases) { ot in + Text(ot.description) } } - Text("Units displayed on the device screen") + Text("Override automatic OLED screen detection.") .foregroundColor(.gray) .font(.callout) } @@ -138,7 +133,6 @@ struct DisplayConfig: View { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) if connectedNode != nil { var dc = Config.DisplayConfig() - dc.gpsFormat = GpsFormats(rawValue: gpsFormat)!.protoEnumValue() dc.screenOnSecs = UInt32(screenOnSeconds) dc.autoScreenCarouselSecs = UInt32(screenCarouselInterval) dc.compassNorthTop = compassNorthTop @@ -148,6 +142,7 @@ struct DisplayConfig: View { dc.displaymode = DisplayModes(rawValue: displayMode)!.protoEnumValue() dc.units = Units(rawValue: units)!.protoEnumValue() dc.use12HClock = use12HourClock + dc.headingBold = headingBold let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: connectedNode!.user!, toUser: node!.user!) if adminMessageId > 0 { @@ -203,9 +198,6 @@ struct DisplayConfig: View { .onChange(of: wakeOnTapOrMotion) { oldWakeOnTapOrMotion, newWakeOnTapOrMotion in if oldWakeOnTapOrMotion != newWakeOnTapOrMotion && newWakeOnTapOrMotion != node?.displayConfig?.wakeOnTapOrMotion { hasChanges = true } } - .onChange(of: gpsFormat) { oldGpsFormat, newGpsFormat in - if oldGpsFormat != newGpsFormat && newGpsFormat != node?.displayConfig?.gpsFormat ?? -1 { hasChanges = true } - } .onChange(of: flipScreen) { oldFlipScreen, newFlipScreen in if oldFlipScreen != newFlipScreen && newFlipScreen != node?.displayConfig?.flipScreen { hasChanges = true } } @@ -221,18 +213,23 @@ struct DisplayConfig: View { .onChange(of: use12HourClock) { oldUse12HourClock, newUse12HourClock in if oldUse12HourClock != newUse12HourClock && newUse12HourClock != node?.displayConfig?.use12HClock { hasChanges = true } } + .onChange(of: headingBold) { oldHeadingBold, newHeadingBold in + if oldHeadingBold != newHeadingBold && newHeadingBold != node?.displayConfig?.headingBold { hasChanges = true } + } + + headingBold } func setDisplayValues() { - self.gpsFormat = Int(node?.displayConfig?.gpsFormat ?? 0) - self.screenOnSeconds = Int(node?.displayConfig?.screenOnSeconds ?? 0) - self.screenCarouselInterval = Int(node?.displayConfig?.screenCarouselInterval ?? 0) - self.compassNorthTop = node?.displayConfig?.compassNorthTop ?? false - self.wakeOnTapOrMotion = node?.displayConfig?.wakeOnTapOrMotion ?? false - self.flipScreen = node?.displayConfig?.flipScreen ?? false - self.oledType = Int(node?.displayConfig?.oledType ?? 0) - self.displayMode = Int(node?.displayConfig?.displayMode ?? 0) - self.units = Int(node?.displayConfig?.units ?? 0) - self.use12HourClock = node?.displayConfig?.use12HClock ?? false - self.hasChanges = node?.displayConfig?.use12HClock ?? false + self.screenOnSeconds = Int(node?.displayConfig?.screenOnSeconds ?? 0) + self.screenCarouselInterval = Int(node?.displayConfig?.screenCarouselInterval ?? 0) + self.compassNorthTop = node?.displayConfig?.compassNorthTop ?? false + self.wakeOnTapOrMotion = node?.displayConfig?.wakeOnTapOrMotion ?? false + self.flipScreen = node?.displayConfig?.flipScreen ?? false + self.oledType = Int(node?.displayConfig?.oledType ?? 0) + self.displayMode = Int(node?.displayConfig?.displayMode ?? 0) + self.units = Int(node?.displayConfig?.units ?? 0) + self.use12HourClock = node?.displayConfig?.use12HClock ?? false + self.headingBold = node?.displayConfig?.headingBold ?? false + self.hasChanges = node?.displayConfig?.use12HClock ?? false } }