Kacheln und Fenster sprechen dieselbe Sprache
Alle Kacheln, Popovers und Fenster auf die Designschicht umgestellt: rund hundert gesetzte Schriftgrößen und 159 gesetzte Abstände und Radien sind jetzt Token. Übrig bleibt `spacing: 0` — das ist eine Aussage, keine geratene Zahl. Die Einstellungen bekommen eine Seitenleiste statt sieben Reitern, deren deutsche Beschriftungen zusammen 880 Punkte brauchten. Panel-Token stehen nicht mehr in Fenstern: dort gilt Systemsemantik, damit der Hellmodus nicht schwarz auf schwarz endet. Neu ist ein Schaufenster, das alle Bauteile nebeneinander zeigt — ohne das lässt sich eine Änderung an einem Token nur prüfen, indem man die App bedient, bis jede Kachel einmal zu sehen war. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9b600de9a9
commit
edb327cabe
@@ -195,12 +195,15 @@ private struct WeatherWidgetView: View {
|
||||
if let lastKnown {
|
||||
content(lastKnown, isStale: true)
|
||||
} else {
|
||||
Notice(symbol: "wifi.slash", text: "widget.weather.unavailable")
|
||||
OnyxNotice(symbol: "wifi.slash",
|
||||
text: String(localized: "widget.weather.unavailable", bundle: .module))
|
||||
}
|
||||
case .locationDenied:
|
||||
Notice(symbol: "location.slash", text: "widget.weather.locationDenied")
|
||||
OnyxNotice(symbol: "location.slash",
|
||||
text: String(localized: "widget.weather.locationDenied", bundle: .module))
|
||||
case .locationUndetermined:
|
||||
Notice(symbol: "location.circle", text: "widget.weather.locationUndetermined")
|
||||
OnyxNotice(symbol: "location.circle",
|
||||
text: String(localized: "widget.weather.locationUndetermined", bundle: .module))
|
||||
case .loading, .idle:
|
||||
ProgressView()
|
||||
.controlSize(.small)
|
||||
@@ -217,25 +220,6 @@ private struct WeatherWidgetView: View {
|
||||
WideWeather(snapshot: snapshot, isStale: isStale)
|
||||
}
|
||||
}
|
||||
|
||||
private struct Notice: View {
|
||||
let symbol: String
|
||||
let text: LocalizedStringKey
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 6) {
|
||||
Image(systemName: symbol)
|
||||
.font(.system(size: 15))
|
||||
.foregroundStyle(Onyx.Color.textTertiary)
|
||||
Text(text, bundle: .module)
|
||||
.font(Onyx.Font.caption)
|
||||
.foregroundStyle(Onyx.Color.textSecondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
private struct WideWeather: View {
|
||||
let snapshot: WeatherSnapshot
|
||||
let isStale: Bool
|
||||
@@ -246,15 +230,15 @@ private struct WideWeather: View {
|
||||
// die untere Hälfte war leer — bei Schriftgrößen von acht Punkten, die
|
||||
// man auf Armlänge nicht entziffert.
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
HStack(alignment: .center, spacing: Onyx.Space.row) {
|
||||
Image(systemName: snapshot.condition.symbolName(isDaylight: snapshot.isDaylight))
|
||||
.font(.system(size: 34))
|
||||
.font(.system(size: Onyx.Symbol.hero))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(Onyx.Color.textPrimary)
|
||||
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(snapshot.temperature.onyxFormatted)
|
||||
.font(.system(size: 30, weight: .medium))
|
||||
.font(Onyx.Font.displayLarge)
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(Onyx.Color.textPrimary)
|
||||
if let high = snapshot.high, let low = snapshot.low {
|
||||
@@ -271,7 +255,7 @@ private struct WideWeather: View {
|
||||
.font(Onyx.Font.caption)
|
||||
.foregroundStyle(Onyx.Color.textSecondary)
|
||||
.lineLimit(1)
|
||||
.padding(.top, 2)
|
||||
.padding(.top, Onyx.Space.xxs)
|
||||
|
||||
if snapshot.apparentTemperature != snapshot.temperature {
|
||||
Text("weather.feelsLike \(snapshot.apparentTemperature.onyxFormatted)",
|
||||
@@ -283,19 +267,19 @@ private struct WideWeather: View {
|
||||
Spacer(minLength: 6)
|
||||
|
||||
if !snapshot.hourly.isEmpty {
|
||||
Divider().overlay(Onyx.Color.hairline)
|
||||
OnyxHairline()
|
||||
|
||||
// Vier statt fünf Stunden: bei 180 Punkten Breite bleiben so
|
||||
// gut vierzig je Spalte, und die Zahlen lassen sich in einer
|
||||
// lesbaren Größe setzen.
|
||||
HStack(spacing: 0) {
|
||||
ForEach(snapshot.hourly.prefix(4)) { point in
|
||||
VStack(spacing: 3) {
|
||||
VStack(spacing: Onyx.Space.xs) {
|
||||
Text(point.date.formatted(.dateTime.hour()))
|
||||
.font(Onyx.Font.metricSmall)
|
||||
.foregroundStyle(Onyx.Color.textTertiary)
|
||||
Image(systemName: point.condition.symbolName(isDaylight: true))
|
||||
.font(.system(size: 13))
|
||||
.font(.system(size: Onyx.Symbol.medium))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(Onyx.Color.textSecondary)
|
||||
Text(point.temperature.onyxFormatted)
|
||||
@@ -306,15 +290,15 @@ private struct WideWeather: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
.padding(.vertical, Onyx.Space.md)
|
||||
}
|
||||
|
||||
Spacer(minLength: 0)
|
||||
|
||||
HStack(spacing: 4) {
|
||||
HStack(spacing: Onyx.Space.xs) {
|
||||
if isStale {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.font(.system(size: 9))
|
||||
.font(.system(size: Onyx.Symbol.caption))
|
||||
.foregroundStyle(Onyx.Color.warning)
|
||||
}
|
||||
Text(stampText)
|
||||
@@ -338,10 +322,13 @@ private struct WideWeather: View {
|
||||
}
|
||||
}
|
||||
|
||||
extension Measurement where UnitType == UnitTemperature {
|
||||
public extension Measurement where UnitType == UnitTemperature {
|
||||
/// Ganzzahlig und in der Einheit, die zur Region des Nutzers passt.
|
||||
/// Nachkommastellen bei der Außentemperatur täuschen eine Genauigkeit vor,
|
||||
/// die die Vorhersage nicht hat.
|
||||
///
|
||||
/// Öffentlich, seit die Temperatur auch neben der Notch steht: dieselbe
|
||||
/// Zahl zweimal verschieden zu runden wäre der Anfang zweier Wahrheiten.
|
||||
var onyxFormatted: String {
|
||||
formatted(.measurement(width: .narrow,
|
||||
usage: .weather,
|
||||
|
||||
Reference in New Issue
Block a user