Weatherkit widgets

This commit is contained in:
Garth Vander Houwen 2024-07-11 08:42:27 -07:00
parent 321a41d3f8
commit 796c1abb31
7 changed files with 143 additions and 1 deletions

View file

@ -6953,6 +6953,9 @@
},
"Enter DFU Mode" : {
},
"Environment" : {
},
"Environment Metrics Log" : {
@ -8265,6 +8268,9 @@
},
"Humidity" : {
},
"HUMIDITY" : {
},
"hybrid" : {
"extractionState" : "migrated",
@ -20839,6 +20845,9 @@
},
"The compass heading on the screen outside of the circle will always point north." : {
},
"The dew point is %@ right now." : {
},
"The fastest that position updates will be sent if the minimum distance has been satisfied" : {

View file

@ -68,6 +68,7 @@
DD3CC6BE28E4CD9800FA9159 /* BatteryGauge.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */; };
DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BF28E7A60700FA9159 /* MessagingEnums.swift */; };
DD3CC6C228EB9D4900FA9159 /* UpdateCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6C128EB9D4900FA9159 /* UpdateCoreData.swift */; };
DD3D17E02C3FB67200561584 /* LocalWeatherConditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3D17DF2C3FB67200561584 /* LocalWeatherConditions.swift */; };
DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582528582E9B009B0E59 /* DeviceConfig.swift */; };
DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD415827285859C4009B0E59 /* TelemetryConfig.swift */; };
DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582928585C32009B0E59 /* RangeTestConfig.swift */; };
@ -294,6 +295,7 @@
DD3CC6BF28E7A60700FA9159 /* MessagingEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingEnums.swift; sourceTree = "<group>"; };
DD3CC6C128EB9D4900FA9159 /* UpdateCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCoreData.swift; sourceTree = "<group>"; };
DD3D17DC2C3D7B1400561584 /* MeshtasticDataModelV 39.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 39.xcdatamodel"; sourceTree = "<group>"; };
DD3D17DF2C3FB67200561584 /* LocalWeatherConditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalWeatherConditions.swift; sourceTree = "<group>"; };
DD41582528582E9B009B0E59 /* DeviceConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceConfig.swift; sourceTree = "<group>"; };
DD415827285859C4009B0E59 /* TelemetryConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryConfig.swift; sourceTree = "<group>"; };
DD41582928585C32009B0E59 /* RangeTestConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RangeTestConfig.swift; sourceTree = "<group>"; };
@ -605,6 +607,7 @@
DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */,
DD354FD82BD96A0B0061A25F /* IAQScale.swift */,
DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */,
DD3D17DF2C3FB67200561584 /* LocalWeatherConditions.swift */,
);
path = Weather;
sourceTree = "<group>";
@ -1134,6 +1137,7 @@
DDDB444C29F8AAA600EE2349 /* Color.swift in Sources */,
DDB8F4122A9EE5DD00230ECE /* UserList.swift in Sources */,
DDB75A0F2A05920E006ED576 /* FileManager.swift in Sources */,
DD3D17E02C3FB67200561584 /* LocalWeatherConditions.swift in Sources */,
DD1933782B084F4200771CD5 /* Measurement.swift in Sources */,
DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */,
DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */,

View file

@ -89,6 +89,7 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View file

@ -1,5 +1,5 @@
{
"originHash" : "c5be9820b6e5add3da0e3bd134c3826b3eece5f926d667cb3800a26572f9e63c",
"originHash" : "74b3ad6215f078d89f4436b6ce0e318f145842efa3453bbe055ab76057de7d6b",
"pins" : [
{
"identity" : "cocoamqtt",

View file

@ -10,6 +10,14 @@ import CoreData
extension NodeInfoEntity {
var latestPosition: PositionEntity? {
return self.positions?.lastObject as? PositionEntity
}
var latestEnvironmentMetrics: TelemetryEntity? {
return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")).lastObject as? TelemetryEntity
}
var hasPositions: Bool {
return positions?.count ?? 0 > 0
}

View file

@ -0,0 +1,114 @@
//
// LocalWeatherConditions.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 7/9/24.
//
import SwiftUI
import MapKit
import WeatherKit
import OSLog
struct LocalWeatherConditions: View {
@State var location: CLLocation?
/// Weather
/// The current weather condition for the city.
@State private var condition: WeatherCondition?
@State private var temperature: Measurement<UnitTemperature>?
@State private var temperatureCompact: String?
@State private var dewPoint: Measurement<UnitTemperature>?
@State private var dewPointString: String?
@State private var humidity: Int?
@State private var pressure: Measurement<UnitPressure>?
@State private var symbolName: String = "cloud.fill"
@State private var attributionLink: URL?
@State private var attributionLogo: URL?
@Environment(\.colorScheme) var colorScheme: ColorScheme
var body: some View {
if location != nil {
ZStack {
VStack {
HStack {
VStack {
VStack(alignment: .leading) {
Text(temperatureCompact ?? "??")
.font(.largeTitle)
Text(condition?.description ?? "??")
.font(.title3)
Image(systemName: symbolName).resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
}
.padding()
}
.background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
.frame(maxWidth: 225, maxHeight: 225)
VStack {
VStack(alignment: .leading) {
Label { Text("HUMIDITY") } icon: { Image(systemName: "humidity").symbolRenderingMode(.multicolor) }
.font(.caption)
VStack(alignment: .leading) {
Text("\(humidity ?? 0)%")
.font(.largeTitle)
.padding(.bottom)
Text("The dew point is \(temperatureCompact ?? "?") right now.")
.lineLimit(3)
.fixedSize(horizontal: false, vertical: true)
.font(.caption)
}
}
.padding()
}
.background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
.frame(maxWidth: 225, maxHeight: 225)
}
}
}
VStack {
HStack {
AsyncImage(url: attributionLogo) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
ProgressView()
.controlSize(.mini)
}
.frame(height: 10)
Link("Other data sources", destination: attributionLink ?? URL(string: "https://weather-data.apple.com/legal-attribution.html")!)
.font(.caption2)
}
.padding(5)
}
.task {
do {
if location != nil {
let weather = try await WeatherService.shared.weather(for: location!)
let numFormatter = NumberFormatter()
let measurementFormatter = MeasurementFormatter()
numFormatter.maximumFractionDigits = 0
measurementFormatter.numberFormatter = numFormatter
measurementFormatter.unitStyle = .short
condition = weather.currentWeather.condition
temperature = weather.currentWeather.temperature
temperatureCompact = measurementFormatter.string(from: dewPoint ?? Measurement<UnitTemperature>(value: 0, unit: .celsius))
dewPoint = weather.currentWeather.dewPoint
humidity = Int(weather.currentWeather.humidity * 100)
pressure = weather.currentWeather.pressure
symbolName = weather.currentWeather.symbolName
let attribution = try await WeatherService.shared.attribution
attributionLink = attribution.legalPageURL
attributionLogo = colorScheme == .light ? attribution.combinedMarkLightURL : attribution.combinedMarkDarkURL
}
} catch {
Logger.services.error("Could not gather weather information: \(error.localizedDescription)")
condition = .clear
symbolName = "cloud.fill"
}
}
.padding(5)
}
}
}

View file

@ -157,6 +157,12 @@ struct NodeDetail: View {
}
}
}
// if node.hasEnvironmentMetrics {
Section("Environment") {
LocalWeatherConditions(location: node.latestPosition?.nodeLocation)
}
// }
Section("Logs") {
// Metrics