1 Commits
Author SHA1 Message Date
BiasFandClaude Opus 5 812874baef Kühlbox-Kachel: "Soll" dazuschreiben, Betriebsart gross, Hinweis nach vorn
Auf der Kachel stand eine nackte Zahl, und das ist genau die Zahl, die
man für die Innentemperatur hält. Jetzt steht "Soll" darüber – bei zwei
Zonen "Soll links", mit "Soll rechts" gleich daneben statt in der
Nebenwertzeile.

Die Betriebsart bekommt ein eigenes Schild in Titelgrösse, rechts auf
Höhe des Sollwerts: Eco oder Max in der Akzentfarbe hinterlegt, Aus grau.
Ob die Box überhaupt läuft, ist die zweite Frage nach dem Sollwert, und
Platz ist auf der Kachel reichlich.

In der Fusszeile steht der Hinweis aufs Verbinden jetzt vorn: "Verbindet
erst beim Öffnen · zuletzt gestellt vor 12 Minuten". Er erklärt, warum
hier kein Messwert steht – das ist die Frage, die sich zuerst stellt, das
Alter kommt danach.

Im Vorführbetrieb steht die Kühlbox ebenfalls auf "zuletzt gestellt"
statt live. Sonst zeigt er ein Verhalten, das es nicht mehr gibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 22:21:09 +02:00
2 changed files with 74 additions and 5 deletions
@@ -262,6 +262,13 @@ final class BluetoothManager: NSObject {
for snapshot in DemoData.snapshots() { for snapshot in DemoData.snapshots() {
snapshots[snapshot.deviceID] = snapshot snapshots[snapshot.deviceID] = snapshot
linkStates[snapshot.deviceID] = .live linkStates[snapshot.deviceID] = .live
// Die Kühlbox wird nur beim Öffnen verbunden im Vorführbetrieb
// steht sie deshalb wie im Alltag auf zuletzt gestellt.
if snapshot.deviceID == DemoData.fridge.id,
let settings = DemoData.fridgeState.settings {
linkStates[snapshot.deviceID] = .idle
snapshots[snapshot.deviceID] = settings.snapshot(deviceID: snapshot.deviceID)
}
if let value = snapshot.primaryMetric?.value { if let value = snapshot.primaryMetric?.value {
history[snapshot.deviceID] = DemoData.history(for: snapshot.deviceID, around: value) history[snapshot.deviceID] = DemoData.history(for: snapshot.deviceID, around: value)
} }
+67 -5
View File
@@ -11,7 +11,9 @@ struct DeviceCard: View {
VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 12) {
header header
if let snapshot, let primary = snapshot.primaryMetric { if isShowingLastSettings, let snapshot {
lastSettings(for: snapshot)
} else if let snapshot, let primary = snapshot.primaryMetric {
HStack(alignment: .firstTextBaseline, spacing: 4) { HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(primary.formatted) Text(primary.formatted)
.font(.system(size: 44, weight: .semibold, design: .rounded)) .font(.system(size: 44, weight: .semibold, design: .rounded))
@@ -54,6 +56,65 @@ struct DeviceCard: View {
} }
} }
/// Ob hier der zuletzt gestellte Stand steht statt Messwerten.
private var isShowingLastSettings: Bool {
device.role.connectsOnDemand && linkState != .live
}
/// Die Kachel der Kühlbox, solange sie nicht verbunden ist.
///
/// Hier steht kein Messwert, sondern was zuletzt eingestellt war also
/// gehört Soll dazu. Ohne das läse man die Zahl als Innentemperatur, und
/// genau dieser Irrtum wäre teuer.
private func lastSettings(for snapshot: DeviceSnapshot) -> some View {
HStack(alignment: .top, spacing: 12) {
VStack(alignment: .leading, spacing: 2) {
Text(snapshot.metrics.count > 1 ? "Soll links" : "Soll")
.font(.caption)
.foregroundStyle(.secondary)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(snapshot.primaryMetric?.formatted ?? "")
.font(.system(size: 44, weight: .semibold, design: .rounded))
Text(snapshot.primaryMetric?.unit ?? "")
.font(.title3.weight(.medium))
.foregroundStyle(.secondary)
}
}
if let right = snapshot.metrics.first(where: { $0.key == "target_right" }),
right.value != nil {
VStack(alignment: .leading, spacing: 2) {
Text("Soll rechts")
.font(.caption)
.foregroundStyle(.secondary)
Text(right.formattedWithUnit)
.font(.title2.weight(.semibold))
.monospacedDigit()
}
}
Spacer(minLength: 0)
modeBadge(snapshot.state)
}
}
/// Betriebsart als Schild: Auf der Kachel ist Platz, und ob die Box läuft
/// oder aus ist, ist die zweite Frage nach dem Sollwert.
@ViewBuilder
private func modeBadge(_ state: String?) -> some View {
if let state {
let isOff = state == "Aus"
Text(state)
.font(.title3.weight(.semibold))
.foregroundStyle(isOff ? Color.secondary : Color.accentColor)
.padding(.horizontal, 14)
.padding(.vertical, 8)
.background(isOff ? Color.secondary.opacity(0.15)
: Color.accentColor.opacity(0.15),
in: .rect(cornerRadius: 12))
}
}
private func secondaryValues(for snapshot: DeviceSnapshot) -> some View { private func secondaryValues(for snapshot: DeviceSnapshot) -> some View {
let others = snapshot.metrics let others = snapshot.metrics
.filter { $0.id != snapshot.primaryMetric?.id && $0.value != nil } .filter { $0.id != snapshot.primaryMetric?.id && $0.value != nil }
@@ -76,7 +137,7 @@ struct DeviceCard: View {
@ViewBuilder @ViewBuilder
private var footer: some View { private var footer: some View {
if device.role.connectsOnDemand, linkState != .live, let snapshot { if isShowingLastSettings, let snapshot {
// Kein Messwert, sondern der zuletzt gestellte Stand. Das gehört // Kein Messwert, sondern der zuletzt gestellte Stand. Das gehört
// dazugeschrieben, sonst liest man ihn als aktuelle Temperatur. // dazugeschrieben, sonst liest man ihn als aktuelle Temperatur.
Text(lastSetText(snapshot)) Text(lastSetText(snapshot))
@@ -104,10 +165,11 @@ struct DeviceCard: View {
} }
/// Was unter einem Gerät steht, das nur beim Öffnen verbunden wird. /// Was unter einem Gerät steht, das nur beim Öffnen verbunden wird.
///
/// Der Hinweis aufs Verbinden steht vorn: Er erklärt, warum hier kein
/// Messwert steht, und das ist die Frage, die sich zuerst stellt.
private func lastSetText(_ snapshot: DeviceSnapshot) -> String { private func lastSetText(_ snapshot: DeviceSnapshot) -> String {
let age = relativeUpdate(snapshot.timestamp) "Verbindet erst beim Öffnen · zuletzt gestellt \(relativeUpdate(snapshot.timestamp))"
guard let state = snapshot.state else { return "Zuletzt gestellt \(age)" }
return "\(state) · zuletzt gestellt \(age)"
} }
/// vor 3 Minuten statt einer Uhrzeit auf der Kachel zählt das Alter. /// vor 3 Minuten statt einer Uhrzeit auf der Kachel zählt das Alter.