TempTrack-iOS/TempTrack/ContentView.swift
2023-06-14 16:16:56 +02:00

184 lines
5.3 KiB
Swift

import SwiftUI
import SFSafeSymbols
struct ContentView: View {
private let minTempColor = Color(hue: 0.624, saturation: 0.5, brightness: 1.0)
private let minTemperature = -20.0
private let maxTempColor = Color(hue: 1.0, saturation: 0.5, brightness: 1.0)
private let maxTemperature = 40.0
private let disconnectedColor = Color(white: 0.8)
@EnvironmentObject
var bluetoothClient: BluetoothClient
@EnvironmentObject
var storage: TemperatureStorage
@State
var showDeviceInfo = false
@State
var showHistory = false
@State
var showLog = false
init() {
}
var averageTemperature: Double? {
let t1 = bluetoothClient.deviceInfo?.sensor1?.optionalValue
guard let t0 = bluetoothClient.deviceInfo?.sensor0?.optionalValue else {
return t1
}
guard let t1 else {
return t0
}
return (t0 + t1) / 2
}
var hasTemperature: Bool {
averageTemperature != nil
}
var temperatureString: String {
guard let temp = averageTemperature else {
return "?"
}
return String(format: "%.0f°", locale: .current, temp)
}
var temperatureIcon: SFSymbol {
guard let temp = averageTemperature else {
return .thermometerMediumSlash
}
guard temp > 0 else {
return .thermometerSnowflake
}
guard temp > 15 else {
return .thermometerLow
}
guard temp > 25 else {
return .thermometerMedium
}
return .thermometerHigh
}
var backgroundColor: Color {
guard let temp = averageTemperature else {
return disconnectedColor
}
guard temp > minTemperature else {
return minTempColor
}
guard temp < maxTemperature else {
return maxTempColor
}
let ratio = (temp - minTemperature) / (maxTemperature - minTemperature)
return minTempColor.blend(to: maxTempColor, intensity: ratio)
}
var backgroundGradient: Gradient {
let color = backgroundColor
let lighter = color.opacity(0.5)
return .init(colors: [lighter, color])
}
var body: some View {
VStack {
Spacer()
// Image(systemSymbol: temperatureIcon)
// .font(.system(size: 100, weight: .light))
if hasTemperature {
Text(temperatureString)
.font(.system(size: 150, weight: .light))
.foregroundColor(.white)
}
Spacer()
Button {
self.showHistory = true
} label: {
TemperatureHistoryChart(points: $storage.recentMeasurements)
.frame(height: 150)
.background(Color.white.opacity(0.1))
.cornerRadius(8)
}
HStack(alignment: .center) {
Button {
self.showLog.toggle()
} label: {
Image(systemSymbol: .textBubble)
.font(.system(size: 30, weight: .light))
.foregroundColor(.white)
}
Spacer()
Button {
self.showDeviceInfo = true
} label: {
if bluetoothClient.hasInfo {
Image(systemSymbol: .iphone)
.font(.system(size: 30, weight: .light))
}
Text(bluetoothClient.deviceState.text)
}
.disabled(!bluetoothClient.hasInfo)
.foregroundColor(.white)
Spacer()
Button {
bluetoothClient.collectRecordedData()
} label: {
Image(systemSymbol: .arrowUpArrowDownCircle)
.font(.system(size: 30, weight: .light))
.foregroundColor(.white)
}.disabled(!bluetoothClient.isConnected)
}.padding()
}
.padding()
.sheet(isPresented: $showDeviceInfo) {
if let info = bluetoothClient.deviceInfo {
DeviceInfoView(info: info, isPresented: $showDeviceInfo)
} else {
EmptyView()
}
}
.sheet(isPresented: $showHistory) {
HistoryList()
.environmentObject(storage)
}
.sheet(isPresented: $showLog) {
LogView()
.environmentObject(log)
}
.background(backgroundGradient)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let storage = TemperatureStorage(lastMeasurements: TemperatureMeasurement.mockData)
let client = BluetoothClient(storage: storage, deviceInfo: .mock)
ContentView()
.environmentObject(storage)
.environmentObject(client)
}
}
extension HorizontalAlignment {
private struct InfoTextAlignment: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[HorizontalAlignment.leading]
}
}
static let infoTextAlignmentGuide = HorizontalAlignment(
InfoTextAlignment.self
)
}