mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
IAQ legend, basic AQI options.
This commit is contained in:
parent
3aa924c954
commit
52dd086e09
6 changed files with 242 additions and 75 deletions
|
|
@ -88,7 +88,7 @@
|
|||
DD5E5211298EE33B00D21B61 /* remote_hardware.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FF298EE33B00D21B61 /* remote_hardware.pb.swift */; };
|
||||
DD5E5212298EE33B00D21B61 /* apponly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E5200298EE33B00D21B61 /* apponly.pb.swift */; };
|
||||
DD5E5213298EE33B00D21B61 /* deviceonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E5201298EE33B00D21B61 /* deviceonly.pb.swift */; };
|
||||
DD5E523F298F5A9E00D21B61 /* AirQualityIndexCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E523E298F5A9E00D21B61 /* AirQualityIndexCompact.swift */; };
|
||||
DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E523E298F5A9E00D21B61 /* AirQualityIndex.swift */; };
|
||||
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */; };
|
||||
DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; };
|
||||
DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; };
|
||||
|
|
@ -341,7 +341,7 @@
|
|||
DD5E51FF298EE33B00D21B61 /* remote_hardware.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = remote_hardware.pb.swift; sourceTree = "<group>"; };
|
||||
DD5E5200298EE33B00D21B61 /* apponly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = apponly.pb.swift; sourceTree = "<group>"; };
|
||||
DD5E5201298EE33B00D21B61 /* deviceonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = deviceonly.pb.swift; sourceTree = "<group>"; };
|
||||
DD5E523E298F5A9E00D21B61 /* AirQualityIndexCompact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirQualityIndexCompact.swift; sourceTree = "<group>"; };
|
||||
DD5E523E298F5A9E00D21B61 /* AirQualityIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirQualityIndex.swift; sourceTree = "<group>"; };
|
||||
DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalNotificationConfig.swift; sourceTree = "<group>"; };
|
||||
DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfig.swift; sourceTree = "<group>"; };
|
||||
DD6193782863875F00E59241 /* SerialConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfig.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -651,7 +651,7 @@
|
|||
DD5E523D298F5A7D00D21B61 /* Weather */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DD5E523E298F5A9E00D21B61 /* AirQualityIndexCompact.swift */,
|
||||
DD5E523E298F5A9E00D21B61 /* AirQualityIndex.swift */,
|
||||
DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */,
|
||||
DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */,
|
||||
DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */,
|
||||
|
|
@ -1207,7 +1207,7 @@
|
|||
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */,
|
||||
DD0E20FD2B87090400F2D100 /* clientonly.pb.swift in Sources */,
|
||||
D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */,
|
||||
DD5E523F298F5A9E00D21B61 /* AirQualityIndexCompact.swift in Sources */,
|
||||
DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */,
|
||||
DD964FBF296E76EF007C176F /* WaypointFormMapKit.swift in Sources */,
|
||||
DD3501892852FC3B000FC853 /* Settings.swift in Sources */,
|
||||
DDDC22382BA92344002C44F1 /* MeshMapContent.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,69 @@
|
|||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
enum Aqi: Int, CaseIterable, Identifiable {
|
||||
case good = 0
|
||||
case moderate = 1
|
||||
case sensitive = 2
|
||||
case unhealthy = 3
|
||||
case veryUnhealthy = 4
|
||||
case hazardous = 5
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
switch self {
|
||||
case .good:
|
||||
return "Good"
|
||||
case .moderate:
|
||||
return "Moderate"
|
||||
case .sensitive:
|
||||
return "Unhealthy for Sensitive Groups"
|
||||
case .unhealthy:
|
||||
return "Unhealthy"
|
||||
case .veryUnhealthy:
|
||||
return "Very Unhealthy"
|
||||
case .hazardous:
|
||||
return "Hazardous"
|
||||
}
|
||||
}
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .good:
|
||||
return .green
|
||||
case .moderate:
|
||||
return .yellow
|
||||
case .sensitive:
|
||||
return .orange
|
||||
case .unhealthy:
|
||||
return .red
|
||||
case .veryUnhealthy:
|
||||
return .purple
|
||||
case .hazardous:
|
||||
return .magenta
|
||||
}
|
||||
}
|
||||
static func getAqi(for value: Int) -> Aqi {
|
||||
let aqi: Aqi
|
||||
switch value {
|
||||
case 0...50:
|
||||
aqi = .good
|
||||
case 51...100:
|
||||
aqi = .moderate
|
||||
case 101...150:
|
||||
aqi = .sensitive
|
||||
case 151...200:
|
||||
aqi = .unhealthy
|
||||
case 201...300:
|
||||
aqi = .veryUnhealthy
|
||||
case 301...500:
|
||||
aqi = .hazardous
|
||||
default:
|
||||
fatalError("Invalid int value")
|
||||
}
|
||||
return aqi
|
||||
}
|
||||
}
|
||||
|
||||
enum Iaq: Int, CaseIterable, Identifiable {
|
||||
case excellent = 0
|
||||
case good = 1
|
||||
|
|
@ -27,7 +90,7 @@ enum Iaq: Int, CaseIterable, Identifiable {
|
|||
case .lightlyPolluted:
|
||||
return "Lightly Polluted"
|
||||
case .moderatelyPolluted:
|
||||
return "Lightly Polluted"
|
||||
return "Moderately Polluted"
|
||||
case .heavilyPolluted:
|
||||
return "Heavily Polluted"
|
||||
case .severelyPolluted:
|
||||
|
|
@ -49,7 +112,7 @@ enum Iaq: Int, CaseIterable, Identifiable {
|
|||
case .heavilyPolluted:
|
||||
return .red
|
||||
case .severelyPolluted:
|
||||
return .purple
|
||||
return .magenta
|
||||
case .extremelyPolluted:
|
||||
return .brown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ extension Color {
|
|||
let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
|
||||
return (brightness > 0.5)
|
||||
}
|
||||
public static var magenta: Color {
|
||||
return Color(UIColor(red: 0.50, green: 0.00, blue: 0.00, alpha: 1.00)) //return Color(UIColor.magenta)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIColor {
|
||||
|
|
|
|||
146
Meshtastic/Views/Helpers/Weather/AirQualityIndex.swift
Normal file
146
Meshtastic/Views/Helpers/Weather/AirQualityIndex.swift
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// AQICircleDisplay.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 2/4/23.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
enum AqiDisplayMode: Int, CaseIterable, Identifiable {
|
||||
|
||||
case pill = 0
|
||||
case dot = 1
|
||||
case text = 2
|
||||
case gauge = 3
|
||||
case gradient = 4
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
}
|
||||
|
||||
struct AirQualityIndex: View {
|
||||
var aqi: Int
|
||||
var displayMode: IaqDisplayMode = .pill
|
||||
let gradient = Gradient(colors: [.green, .yellow, .orange, .red, .purple, .magenta])
|
||||
|
||||
var body: some View {
|
||||
|
||||
let aqiEnum = Aqi.getAqi(for: aqi)
|
||||
switch displayMode {
|
||||
case .pill:
|
||||
ZStack (alignment: .leading) {
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.fill(aqiEnum.color)
|
||||
.frame(width: 125, height: 30)
|
||||
Label("IAQ \(aqi)", systemImage: aqi < 100 ? "aqi.low" : ((aqi > 100 && aqi < 201) ? "aqi.medium" : "aqi.high"))
|
||||
.padding(.leading, 4)
|
||||
}
|
||||
case .dot:
|
||||
VStack {
|
||||
HStack {
|
||||
Text("\(aqi)")
|
||||
Circle()
|
||||
.fill(aqiEnum.color)
|
||||
.frame(width: 10, height: 10)
|
||||
}
|
||||
}
|
||||
case .text:
|
||||
Text(aqiEnum.description)
|
||||
.font(.caption)
|
||||
case .gauge:
|
||||
Gauge(value: Double(aqi), in: 0...500) {
|
||||
|
||||
Text("IAQ")
|
||||
.foregroundColor(aqiEnum.color)
|
||||
} currentValueLabel: {
|
||||
Text("\(Int(aqi))")
|
||||
}
|
||||
.tint(gradient)
|
||||
.gaugeStyle(.accessoryCircular)
|
||||
case .gradient:
|
||||
HStack {
|
||||
Gauge(value: Double(aqi), in: 0...500) {
|
||||
Text("IAQ")
|
||||
.foregroundColor(aqiEnum.color)
|
||||
} currentValueLabel: {
|
||||
Text("IAQ ")+Text("\(Int(aqi))")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.tint(gradient)
|
||||
.gaugeStyle(.accessoryLinear)
|
||||
Text(aqiEnum.description)
|
||||
.font(.caption)
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AirQualityIndex_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
Text(".pill")
|
||||
.font(.title2)
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 6)
|
||||
AirQualityIndex(aqi: 51)
|
||||
}
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 101)
|
||||
AirQualityIndex(aqi: 151)
|
||||
}
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 201)
|
||||
AirQualityIndex(aqi: 351)
|
||||
}
|
||||
Text(".dot")
|
||||
.font(.title2)
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 6, displayMode: .dot)
|
||||
AirQualityIndex(aqi: 51, displayMode: .dot)
|
||||
AirQualityIndex(aqi: 101, displayMode: .dot)
|
||||
AirQualityIndex(aqi: 201, displayMode: .dot)
|
||||
AirQualityIndex(aqi: 350, displayMode: .dot)
|
||||
AirQualityIndex(aqi: 351, displayMode: .dot)
|
||||
}
|
||||
Text(".text")
|
||||
.font(.title2)
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 6, displayMode: .text)
|
||||
AirQualityIndex(aqi: 51, displayMode: .text)
|
||||
AirQualityIndex(aqi: 101, displayMode: .text)
|
||||
}
|
||||
HStack {
|
||||
AirQualityIndex(aqi: 201, displayMode: .text)
|
||||
AirQualityIndex(aqi: 350, displayMode: .text)
|
||||
}
|
||||
Text(".gauge")
|
||||
.font(.title2)
|
||||
HStack (alignment: .top) {
|
||||
AirQualityIndex(aqi: 6, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 51, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 101, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 151, displayMode: .gauge)
|
||||
}
|
||||
HStack (alignment: .top) {
|
||||
AirQualityIndex(aqi: 201, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 251, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 301, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 351, displayMode: .gauge)
|
||||
}
|
||||
HStack (alignment: .top) {
|
||||
AirQualityIndex(aqi: 401, displayMode: .gauge)
|
||||
AirQualityIndex(aqi: 500, displayMode: .gauge)
|
||||
}
|
||||
Text(".gradient")
|
||||
.font(.title2)
|
||||
AirQualityIndex(aqi: 6, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 51, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 101, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 201, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 351, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 401, displayMode: .gradient)
|
||||
AirQualityIndex(aqi: 500, displayMode: .gradient)
|
||||
|
||||
}.previewLayout(.fixed(width: 300, height: 800))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
//
|
||||
// AQICircleDisplay.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 2/4/23.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
struct AirQualityIndexCompact: View {
|
||||
var aqi: Int
|
||||
|
||||
var body: some View {
|
||||
|
||||
HStack(spacing: 0.5) {
|
||||
Text("AQI \(aqi)")
|
||||
.foregroundColor(.gray)
|
||||
.padding(.trailing, 0)
|
||||
.font(.caption)
|
||||
|
||||
if aqi > 0 && aqi < 51 {
|
||||
// Good
|
||||
Circle()
|
||||
.fill(.green)
|
||||
.frame(width: 10, height: 10)
|
||||
} else if aqi > 50 && aqi < 101 {
|
||||
// Satisfactory
|
||||
Circle()
|
||||
.fill(Color(red: 0, green: 0.9882, blue: 0.1804))
|
||||
.frame(width: 10, height: 10)
|
||||
} else if aqi > 100 && aqi < 201 {
|
||||
// Moderate
|
||||
Circle()
|
||||
.fill(.yellow)
|
||||
.frame(width: 10, height: 10)
|
||||
} else if aqi > 200 && aqi < 301 {
|
||||
// Poor
|
||||
Circle()
|
||||
.fill(.orange)
|
||||
.frame(width: 10, height: 10)
|
||||
|
||||
} else if aqi > 300 && aqi < 401 {
|
||||
// Very Poor
|
||||
Circle()
|
||||
.fill(.red)
|
||||
.frame(width: 10, height: 10)
|
||||
} else if aqi >= 401 {
|
||||
// Very Poor
|
||||
Circle()
|
||||
.fill(Color(red: 0.8392, green: 0.0667, blue: 0))
|
||||
.frame(width: 10, height: 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct AQICircleDisplay_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
VStack {
|
||||
AirQualityIndexCompact(aqi: 5)
|
||||
AirQualityIndexCompact(aqi: 51)
|
||||
AirQualityIndexCompact(aqi: 101)
|
||||
AirQualityIndexCompact(aqi: 201)
|
||||
AirQualityIndexCompact(aqi: 301)
|
||||
AirQualityIndexCompact(aqi: 401)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,10 +9,32 @@ 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) {
|
||||
VStack(alignment:.leading) {
|
||||
ForEach(Iaq.allCases) { iaq in
|
||||
HStack {
|
||||
RoundedRectangle(cornerRadius: 5)
|
||||
.fill(iaq.color)
|
||||
.frame(width: 30, height: 20)
|
||||
Text(iaq.description)
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(.white)
|
||||
.cornerRadius(20) /// make the background rounded
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.stroke(.secondary, lineWidth: 4)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct IAQSCalePreviews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
IAQScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue