diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 86eb6681..50002bf1 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */; }; DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */; }; DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; }; + DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD354FD82BD96A0B0061A25F /* IAQScale.swift */; }; DD3619152B1EF9F900C41C8C /* LocationsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */; }; DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */; }; DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */; }; @@ -296,6 +297,7 @@ DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 23.xcdatamodel"; sourceTree = ""; }; DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirmwareApi.swift; sourceTree = ""; }; DD3501882852FC3B000FC853 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; + DD354FD82BD96A0B0061A25F /* IAQScale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAQScale.swift; sourceTree = ""; }; DD3619132B1EE20700C41C8C /* MeshtasticDataModelV21.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV21.xcdatamodel; sourceTree = ""; }; DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsHandler.swift; sourceTree = ""; }; DD398EBD2B93F640002B4C51 /* MeshtasticDataModelV 29.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 29.xcdatamodel"; sourceTree = ""; }; @@ -651,7 +653,9 @@ children = ( DD5E523E298F5A9E00D21B61 /* AirQualityIndexCompact.swift */, DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */, + DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */, DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */, + DD354FD82BD96A0B0061A25F /* IAQScale.swift */, ); path = Weather; sourceTree = ""; @@ -921,7 +925,6 @@ DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */, DDB75A202A12B954006ED576 /* LoRaSignalStrength.swift */, DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */, - DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */, ); path = Helpers; sourceTree = ""; @@ -1239,6 +1242,7 @@ DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */, DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */, DDC94FC129CE063B0082EA6E /* BatteryLevel.swift in Sources */, + DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */, DDDB445429F8AD1600EE2349 /* Data.swift in Sources */, DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */, DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */, @@ -1578,7 +1582,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.3.6; + MARKETING_VERSION = 2.3.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1612,7 +1616,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.3.6; + MARKETING_VERSION = 2.3.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1685,7 +1689,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.3.6; + MARKETING_VERSION = 2.3.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1718,7 +1722,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.3.6; + MARKETING_VERSION = 2.3.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Views/Helpers/CircleText.swift b/Meshtastic/Views/Helpers/CircleText.swift index bb3fa07b..0a348349 100644 --- a/Meshtastic/Views/Helpers/CircleText.swift +++ b/Meshtastic/Views/Helpers/CircleText.swift @@ -29,10 +29,8 @@ struct CircleText: View { struct CircleText_Previews: PreviewProvider { static var previews: some View { - - HStack { - VStack { - + VStack { + HStack { CircleText(text: "N1", color: Color.yellow, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "8", color: Color.purple, circleSize: 80) @@ -41,17 +39,20 @@ struct CircleText_Previews: PreviewProvider { .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "🍔", color: Color.brown, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) + } + HStack { CircleText(text: "👻", color: Color.orange, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "🤙", color: Color.orange, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) - - } - VStack { CircleText(text: "69", color: Color.green, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "WWWW", color: Color.cyan, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) + } + HStack { + + CircleText(text: "CW-A", color: Color.secondary) .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "CW-A", color: Color.secondary, circleSize: 80) @@ -60,7 +61,20 @@ struct CircleText_Previews: PreviewProvider { .previewLayout(.fixed(width: 300, height: 100)) CircleText(text: "IIII", color: Color.accentColor, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) - CircleText(text: "LCP", color: Color.primary, circleSize: 80) + } + HStack { + + CircleText(text: "🚗", color: Color.orange) + .previewLayout(.fixed(width: 300, height: 100)) + CircleText(text: "🔋", color: Color.indigo, circleSize: 80) + .previewLayout(.fixed(width: 300, height: 100)) + CircleText(text: "🛢️", color: Color.orange, circleSize: 80) + .previewLayout(.fixed(width: 300, height: 100)) + CircleText(text: "LCP", color: Color.indigo, circleSize: 80) + .previewLayout(.fixed(width: 300, height: 100)) + } + HStack { + CircleText(text: "🤡", color: Color.red, circleSize: 80) .previewLayout(.fixed(width: 300, height: 100)) } } diff --git a/Meshtastic/Views/Helpers/IndoorAirQuality.swift b/Meshtastic/Views/Helpers/IndoorAirQuality.swift deleted file mode 100644 index fa90d6f5..00000000 --- a/Meshtastic/Views/Helpers/IndoorAirQuality.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// IndoorAirQuality.swift -// Meshtastic -// -// Copyright(c) by Garth Vander Houwen on 4/10/24. -// - -import Foundation -import SwiftUI - -enum IaqDisplayMode: Int, CaseIterable, Identifiable { - - case pill = 0 - case dot = 1 - case text = 2 - case gauge = 3 - - var id: Int { self.rawValue } -} - -struct IndoorAirQuality: View { - var iaq: Int = 0 - var displayMode: IaqDisplayMode = .pill - let gradient = Gradient(colors: [.green, .mint, .yellow, .orange, .red, .purple, .purple, .brown, .brown, .brown, .brown]) - - var body: some View { - let iaqEnum = Iaq.getIaq(for: iaq) - switch displayMode { - case .pill: - ZStack (alignment: .leading) { - RoundedRectangle(cornerRadius: 10) - .fill(iaqEnum.color) - .frame(width: 125, height: 30) - Label("IAQ \(iaq)", systemImage: iaq < 100 ? "aqi.low" : ((iaq > 100 && iaq < 201) ? "aqi.medium" : "aqi.high")) - .padding(.leading, 4) - } - case .dot: - VStack { - HStack { - Text("\(iaq)") - Circle() - .fill(iaqEnum.color) - .frame(width: 10, height: 10) - } - } - case .text: - Text(iaqEnum.description) - .font(.caption) - case .gauge: - Gauge(value: Double(iaq), in: 0...500) { - - Text("IAQ") - .foregroundColor(iaqEnum.color) - } currentValueLabel: { - Text("\(Int(iaq))") - } - .tint(gradient) - .gaugeStyle(.accessoryCircular) - } - } -} - -struct IndoorAirQuality_Previews: PreviewProvider { - static var previews: some View { - VStack { - Text(".pill") - .font(.title) - HStack { - VStack{ - IndoorAirQuality(iaq: 6) - IndoorAirQuality(iaq: 51) - IndoorAirQuality(iaq: 101) - } - VStack { - IndoorAirQuality(iaq: 201) - IndoorAirQuality(iaq: 350) - IndoorAirQuality(iaq: 351) - } - } - Text(".dot") - .font(.title) - HStack { - VStack (alignment: .leading) { - IndoorAirQuality(iaq: 6, displayMode: .dot) - IndoorAirQuality(iaq: 51, displayMode: .dot) - IndoorAirQuality(iaq: 101, displayMode: .dot) - } - VStack (alignment: .leading) { - IndoorAirQuality(iaq: 201, displayMode: .dot) - IndoorAirQuality(iaq: 350, displayMode: .dot) - IndoorAirQuality(iaq: 351, displayMode: .dot) - } - } - Text(".text") - .font(.title) - IndoorAirQuality(iaq: 6, displayMode: .text) - IndoorAirQuality(iaq: 51, displayMode: .text) - IndoorAirQuality(iaq: 101, displayMode: .text) - IndoorAirQuality(iaq: 201, displayMode: .text) - IndoorAirQuality(iaq: 350, displayMode: .text) - IndoorAirQuality(iaq: 351, displayMode: .text) - Text(".gauge") - .font(.title) - HStack (alignment: .top) { - VStack{ - IndoorAirQuality(iaq: 6, displayMode: .gauge) - IndoorAirQuality(iaq: 51, displayMode: .gauge) - IndoorAirQuality(iaq: 101, displayMode: .gauge) - IndoorAirQuality(iaq: 151, displayMode: .gauge) - } - VStack{ - IndoorAirQuality(iaq: 201, displayMode: .gauge) - IndoorAirQuality(iaq: 251, displayMode: .gauge) - IndoorAirQuality(iaq: 301, displayMode: .gauge) - IndoorAirQuality(iaq: 350, displayMode: .gauge) - } - VStack{ - IndoorAirQuality(iaq: 351, displayMode: .gauge) - IndoorAirQuality(iaq: 401, displayMode: .gauge) - IndoorAirQuality(iaq: 500, displayMode: .gauge) - } - } - }.previewLayout(.fixed(width: 300, height: 800)) - } -} diff --git a/Meshtastic/Views/Helpers/Weather/IAQScale.swift b/Meshtastic/Views/Helpers/Weather/IAQScale.swift new file mode 100644 index 00000000..7fa50902 --- /dev/null +++ b/Meshtastic/Views/Helpers/Weather/IAQScale.swift @@ -0,0 +1,18 @@ +// +// IAQScale.swift +// Meshtastic +// +// Created by Garth Vander Houwen on 4/24/24. +// + +import SwiftUI + +struct IAQScale: View { + + let gradient = Gradient(colors: [.green, .mint, .yellow, .orange, .red, .purple, .purple, .brown, .brown, .brown, .brown]) + var body: some View { + ZStack (alignment: .leading) { + + } + } +} diff --git a/Meshtastic/Views/Helpers/Weather/IndoorAirQuality.swift b/Meshtastic/Views/Helpers/Weather/IndoorAirQuality.swift new file mode 100644 index 00000000..5e12aa9a --- /dev/null +++ b/Meshtastic/Views/Helpers/Weather/IndoorAirQuality.swift @@ -0,0 +1,148 @@ +// +// IndoorAirQuality.swift +// Meshtastic +// +// Copyright(c) by Garth Vander Houwen on 4/10/24. +// + +import Foundation +import SwiftUI + +enum IaqDisplayMode: Int, CaseIterable, Identifiable { + + case pill = 0 + case dot = 1 + case text = 2 + case gauge = 3 + case gradient = 4 + + var id: Int { self.rawValue } +} + +struct IndoorAirQuality: View { + var iaq: Int = 0 + var displayMode: IaqDisplayMode = .pill + let gradient = Gradient(colors: [.green, .mint, .yellow, .orange, .red, .purple, .purple, .brown, .brown, .brown, .brown]) + + var body: some View { + let iaqEnum = Iaq.getIaq(for: iaq) + switch displayMode { + case .pill: + ZStack (alignment: .leading) { + RoundedRectangle(cornerRadius: 10) + .fill(iaqEnum.color) + .frame(width: 125, height: 30) + Label("IAQ \(iaq)", systemImage: iaq < 100 ? "aqi.low" : ((iaq > 100 && iaq < 201) ? "aqi.medium" : "aqi.high")) + .padding(.leading, 4) + } + case .dot: + VStack { + HStack { + Text("\(iaq)") + Circle() + .fill(iaqEnum.color) + .frame(width: 10, height: 10) + } + } + case .text: + Text(iaqEnum.description) + .font(.caption) + case .gauge: + Gauge(value: Double(iaq), in: 0...500) { + + Text("IAQ") + .foregroundColor(iaqEnum.color) + } currentValueLabel: { + Text("\(Int(iaq))") + } + .tint(gradient) + .gaugeStyle(.accessoryCircular) + case .gradient: + HStack { + Gauge(value: Double(iaq), in: 0...500) { + Text("IAQ") + .foregroundColor(iaqEnum.color) + } currentValueLabel: { + Text("IAQ ")+Text("\(Int(iaq))") + .foregroundColor(.gray) + } + .tint(gradient) + .gaugeStyle(.accessoryLinear) + Text(iaqEnum.description) + .font(.caption) + } + .padding([.leading, .trailing]) + } + } +} + +struct IndoorAirQuality_Previews: PreviewProvider { + static var previews: some View { + VStack { + Text(".pill") + .font(.title2) + HStack { + IndoorAirQuality(iaq: 6) + IndoorAirQuality(iaq: 51) + } + HStack { + IndoorAirQuality(iaq: 101) + IndoorAirQuality(iaq: 201) + } + HStack { + IndoorAirQuality(iaq: 350) + IndoorAirQuality(iaq: 351) + } + Text(".dot") + .font(.title2) + HStack { + IndoorAirQuality(iaq: 6, displayMode: .dot) + IndoorAirQuality(iaq: 51, displayMode: .dot) + IndoorAirQuality(iaq: 101, displayMode: .dot) + IndoorAirQuality(iaq: 201, displayMode: .dot) + IndoorAirQuality(iaq: 350, displayMode: .dot) + IndoorAirQuality(iaq: 351, displayMode: .dot) + } + Text(".text") + .font(.title2) + HStack { + IndoorAirQuality(iaq: 6, displayMode: .text) + IndoorAirQuality(iaq: 51, displayMode: .text) + IndoorAirQuality(iaq: 101, displayMode: .text) + } + HStack { + IndoorAirQuality(iaq: 201, displayMode: .text) + IndoorAirQuality(iaq: 350, displayMode: .text) + IndoorAirQuality(iaq: 351, displayMode: .text) + } + Text(".gauge") + .font(.title2) + HStack (alignment: .top) { + IndoorAirQuality(iaq: 6, displayMode: .gauge) + IndoorAirQuality(iaq: 51, displayMode: .gauge) + IndoorAirQuality(iaq: 101, displayMode: .gauge) + IndoorAirQuality(iaq: 151, displayMode: .gauge) + } + HStack (alignment: .top) { + IndoorAirQuality(iaq: 201, displayMode: .gauge) + IndoorAirQuality(iaq: 251, displayMode: .gauge) + IndoorAirQuality(iaq: 301, displayMode: .gauge) + IndoorAirQuality(iaq: 351, displayMode: .gauge) + } + HStack (alignment: .top) { + IndoorAirQuality(iaq: 401, displayMode: .gauge) + IndoorAirQuality(iaq: 500, displayMode: .gauge) + } + Text(".gradient") + .font(.title2) + IndoorAirQuality(iaq: 6, displayMode: .gradient) + IndoorAirQuality(iaq: 51, displayMode: .gradient) + IndoorAirQuality(iaq: 101, displayMode: .gradient) + IndoorAirQuality(iaq: 201, displayMode: .gradient) + IndoorAirQuality(iaq: 351, displayMode: .gradient) + IndoorAirQuality(iaq: 401, displayMode: .gradient) + IndoorAirQuality(iaq: 500, displayMode: .gradient) + + }.previewLayout(.fixed(width: 300, height: 800)) + } +} diff --git a/Meshtastic/Views/Settings/Firmware.swift b/Meshtastic/Views/Settings/Firmware.swift index f12ba7db..60f02bd6 100644 --- a/Meshtastic/Views/Settings/Firmware.swift +++ b/Meshtastic/Views/Settings/Firmware.swift @@ -12,7 +12,7 @@ struct Firmware: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager var node: NodeInfoEntity? - @State var minimumVersion = "2.3.5" + @State var minimumVersion = "2.3.7" @State var version = "" @State private var currentDevice: DeviceHardware? @State private var latestStable: FirmwareRelease?