12 KiB
Komponenten: Wetter-Klon (Compose, Material 3 Expressive)
Tokens: tokens.json → Tokens.kt (über gen_theme.py). Komponenten verwenden nur Rollen (WColor.onScene), nie rohe Hex-Werte.
Icons: Material Symbols Rounded (Apache 2.0) für die UI. Die Wettericons sind eigene oder Meteocons (MIT), animiert über Lottie. Kein Google-Artwork.
Schrift: Roboto Flex (OFL). Texte sind alle neu geschrieben, auf Deutsch.
Grundregel Kontrast über Szenen
Text auf dem animierten Himmel nutzt on-scene, bei hellen Szenen (Schnee, Nebel, unterer Tagesverlauf) on-scene-dark. Die Szene meldet ihre Helligkeit (scene.isLight), und das Theme wählt danach.
Beim klaren Tageshimmel oben besteht weißer Text nur als Großtext (3,9:1). Kleiner Text dort braucht deshalb einen Scrim, einen Verlauf von 0 auf 25 % Schwarz hinter dem Hero-Kopf.
Karten auf der Szene: scene-card mit 85 % Deckkraft plus Blur (API 31+, RenderEffect). Ohne Blur wird scene-card voll deckend gezeigt.
WeatherScene (animierter Hintergrund)
variants clear, partly-cloudy, cloudy, rain, drizzle, snow, sleet, storm, fog × day/night; intensity 0..1
layers sky gradient (scene-*-top/bottom) → sun/moon+stars → clouds (AGSL noise) → precipitation particles → lightning flash → fog
states playing, paused (off-screen / lifecycle STOPPED), reduced (battery saver, "Animationen entfernen", setting off → static gradient), transitioning (crossfade 600ms between conditions)
motion parallax 0.3× on scroll, wind direction tilts rain, haptic tick on lightning (if vibrations on, never during severe alert)
a11y decorative: no semantics; condition always also stated in text
perf adaptive quality (particle count by frame time), 30fps cap on low-end
used on S01, S02 (row backgrounds, static), S12 (pre-rendered bitmap)
HeroBlock
content city name (title) + location pin if current, temperature (display 96sp, wdth 125), condition (headline), "Gefühlt 12°" + H/T (body)
states loading (shimmer on numbers, scene neutral), filled, stale ("Stand: vor 2 Std" chip), offline (cloud-off icon chip), no-permission (CTA "Standort erlauben")
tokens on-scene / on-scene-dark, space 24 top
motion temperature counts up on first load (300ms), collapses into app bar on scroll (large → small top app bar)
a11y one merged semantics node: "Berlin, 14 Grad, leicht bewölkt, gefühlt 12, Höchstwert 17, Tiefstwert 9"
used on S01
AlertBanner
variants minor (alert-minor), moderate/severe (alert-severe), extreme (alert-extreme)
content icon, event ("Sturmböen"), agency + validity ("DWD · bis 18:00"), chevron
states single, stacked (n more), expanded (inline first lines), expired (removed with fade)
tokens radius lg, padding 16
a11y liveRegion polite on appear; whole banner is one button "Warnung: Sturmböen, Deutscher Wetterdienst, bis 18 Uhr. Details"
used on S01 (top of cards, replaces Brief), S11
BriefCard
content 1–2 sentences, generated (e.g. "Ab 15 Uhr Regen, abends trocken. Morgen 6° kühler.")
states loading (two shimmer lines), filled, hidden (alert active or setting off)
tokens scene-card, body, radius xl
used on S01
HourlyStrip
content per hour: time label, icon, temp, precip % if ≥ 20 %; sunrise/sunset inserted as items; "Jetzt" first
states loading, filled, scroll; selected-hour (tap shows detail tooltip)
extra temperature line chart behind items (Canvas, smooth cubic)
a11y LazyRow, each item "15 Uhr, 14 Grad, Regen 40 Prozent"
used on S01 (fixed position), S04, S12 (widget variant)
DayRow / DailyList
content weekday ("Heute", "Mo"), icon, precip %, low temp, range bar (gradient cold→warm over the 10-day min..max, dot = current temp today), high temp
states default, pressed (ripple), expanded (inline hourly, optional)
a11y "Montag, Regen 60 Prozent, 8 bis 15 Grad"
used on S01, S12
MetricCard (base for all detail cards)
variants small 1×1, wide 2×1; shapes per tokens.shape (squircle, cookie, arch, pill)
slots header (icon + label), value (metric 32sp), visual (gauge/chart), footer (one-line explanation)
states default, pressed (morph radius→md, spring-fast), dragging (elevation card-drag, scale 1.04, haptic), placeholder (dashed border while dragging), loading, unavailable ("In deiner Region nicht verfügbar")
tokens scene-card / scene-card-light, on-scene, radius lg
a11y button → opens S05; reorder via accessibility actions "Nach oben/unten verschieben"
used on S01, S10
instances
Precip next-hour bar chart (minutely_15) + "Regen in ~20 Min" / total today
Wind compass dial with arrow, speed, gusts, Beaufort label
UV cookie shape, arc 0–11+, colour by band (uv-high etc.), "Sonnenschutz 11–16 Uhr"
Humidity value + dew point, vertical fill
Pressure dial with trend arrow (rising/falling over 3h)
Visibility value + description
Sun arch with sun position dot, sunrise/sunset times, day length
AQI pill scale (aqi-good..aqi-bad), value, main pollutant
Pollen top 3 types with level dots (Europe only, else hidden)
Map static radar preview thumbnail → opens S06
RadarMap (S06)
content MapLibre + OSM base (light/dark style), RainViewer overlay, location dot, attribution
controls timeline scrubber (past 2h … +30min), play/pause FAB, time label, legend
states loading tiles, playing, paused, no-coverage, offline
a11y scrubber is a Slider with "13:40, Vorhersage" values
used on S06
CityRow
content name, admin area, local time, temp, condition icon, H/T; current-location row with pin and not deletable
states default, pressed, swiping (red bg + trash icon reveal), deleted (snackbar "Gelöscht · Rückgängig"), dragging (reorder)
bg static mini scene gradient for the city's condition
motion shared element (name + temp) into S01
used on S02
SearchField + ResultList
states empty (recents), typing (debounced 300ms, progress), results, no results ("Kein Ort gefunden"), error (retry)
a11y SearchBar (M3), results announce count
used on S03
TopAppBar
variants transparent over scene (S01), surface (S02, S08)
content menu/list button, city title (collapsed), settings icon (no account avatar)
used on S01, S02, S08
PagerIndicator
dots for saved cities, current one wide (expressive pill); swipe between cities
used on S01
Settings rows
variants radio group, switch, link row, section header
states default, disabled (with reason text), focused
used on S08, S09
Snackbar, Dialog (permission rationale), Shimmer placeholder: M3 standard with tokens.
Widgets (Glance)
Widget shell
radius widget (24dp, follows system launcher radius on Android 12+)
styles dynamic_color (surface-container from wallpaper), condition (pre-rendered scene bitmap + on-scene text), transparent (text with shadow)
states loading ("…"), filled, stale (small clock icon), no location ("Ort wählen"), error (tap to retry)
tap opens S01 for that city; refresh icon only on ≥ 4×2
NowWidget 2×1: icon + temp | 2×2: + city, condition, H/T
HourlyWidget 4×2: now block + 6 hours (icon, temp, time)
DailyWidget 4×2: now + 5 days | 4×3: + range bars
FullWidget 4×4: now, 5 hours, 5 days, alert line if active
GlanceWidget 4×1: "Fr., 17. Okt. · ☀ 14°" one line, alert replaces date (two lines: event, agency)
type display-widget 44sp for temps, label for times; size by SizeMode.Responsive breakpoints
a11y contentDescription on root summarising the widget
config S12-config activity: location picker, style, live preview, "Fertig"
Screens → Komponenten (Status)
| Screen | Komponenten |
|---|---|
| S01 | WeatherScene, TopAppBar, HeroBlock, AlertBanner, BriefCard, HourlyStrip, DailyList, MetricCard×n, PagerIndicator |
| S02 | TopAppBar, CityRow, SearchField |
| S03 | SearchField, ResultList |
| S04/S05 | HourlyStrip, chart, MetricCard expanded |
| S06 | RadarMap |
| S08/S09 | Settings rows |
| S10 | MetricCard (dragging/placeholder) |
| S11 | AlertBanner expanded, text |
| S12 | Widgets |
Abgleich mit Screenshots (ref-01..04), überschreibt Abweichungen oben
Gemessen an replica/screens/ref-*.png. Das Layout-Muster übernehmen wir, die Grafik zeichnen wir selbst.
- HeroBlock: zentrierte Spalte. Oben die Wetterlage (22sp), darunter die Temperatur sehr groß und fett (112sp, 700, nicht dünn) mit dem Wettericon direkt rechts daneben, etwa 40 % der Ziffernhöhe, oben ausgerichtet. Dann „Gefühlt 19°“ und „Höchstwert 22° · Tiefstwert 14°“. Am Tag ist der Text dunkel auf hellem Himmel, nachts weiß. Es gibt keinen Scrim, die hellen Szenen sind entsprechend hell gewählt.
- Szene: ruhiger, weicher Verlauf mit großen, unscharfen, langsam treibenden Formen (Wolkenschemen, Hügel). Keine fotorealistische Darstellung. Bei Niederschlag fallen dezente Partikel.
- Karten-Container: deckend (
cardbzw.dark-card, warm getöntes Neutral), Radius 28, Padding 20. Die Kopfzeile besteht aus einem Outline-Icon und dem Titel (card-title). Zwischen den Karten 12 dp Abstand, nach außen 16 dp Rand. - HourlyStrip: Die Spalten zeigen Temperatur, darunter Icon, darunter Niederschlag in % (
precip-text, klein), darunter die Uhrzeit. Die aktuelle Stunde trägt einen Cookie-Chip (now-chip) hinter der Temperatur, das Label heißt „Jetzt“. - DailyList: horizontal scrollende Reihe vertikaler Kapseln (
pill, Radius 24, ca. 56×190 dp). In jeder Kapsel stehen Höchstwert, Tiefstwert (muted), Icon, Niederschlag in % und Tag plus Datum. Ein Tipp auf die Kapsel öffnet S04. - DayDetail (S04, bestätigt): oben eine Kapselreihe, die gewählte Kapsel ist hervorgehoben (
pill-selected). Darunter Datum, Ort, „24°/14°“ (day-range 56sp) mit Icon, Wetterlage, die stündliche Vorhersage für diesen Tag und darunter dieselben Detailkarten. - Detailkarten: Raster mit 2 Spalten aus quadratischen Kacheln, Formen statt einheitlicher Karten:
- Wind: Kreis, darin ein abgerundetes Dreieck als Blob (
fill-*), gedreht in die Windrichtung, mittig Wert und Einheit, darunter „Aus NW“ - UV: Cookie mit 12 Wellen, Wert und Stufe, Punkte auf einem unteren Bogen, der aktive Punkt farbig
- Sichtweite: Kreis mit gewellter Innenfläche (
fill-tertiary), Wert und Einheit - Luftfeuchte: Rechteck, Füllstand mit gewellter Oberkante, Höhe = %, unten ein runder Chip mit dem Taupunkt
- Luftdruck: Kreis mit 270°-Bogenanzeige, Wert groß, Einheit darunter
- Sonne: Rechteck mit gefülltem Sinus-Hügel über der Horizontlinie, der Nachtteil dunkler, Sonnenpunkt auf der Kurve, Aufgang und Untergang als Zeiten
- Luftqualität: Rechteck mit Verlaufsbalken und Knopf, Wert, Einstufung („Gute Luftqualität“); ohne Daten wird „– –“ gezeigt
- Wind: Kreis, darin ein abgerundetes Dreieck als Blob (
- NowcastCard (neu): „Regen ab 09:15“ als Titel, Untertitel „Leichter Regen von 09:15 bis 10:45“. Ein Punkt-Balkendiagramm zeigt die nächsten 2–3 Stunden in 15-Minuten-Schritten, die Y-Achse in drei Stufen (leicht, mäßig, stark). Ein Marker-Chip am Beginn, die X-Achse mit Uhrzeiten. Die Karte erscheint nur, wenn in den nächsten 3 Stunden Niederschlag kommt. Daten: Open-Meteo
minutely_15. - BriefCard: wie eine normale Karte mit Icon, Titel „Kurz gesagt“ und einem Chevron zum Auf- und Zuklappen. Darunter 2–3 Sätze Text in body.
- Vorschau eines Orts (S15, neu): Ein gesuchter Ort öffnet die volle Ansicht mit einem Button „Speichern“ oben rechts (gefüllter Pill-Button, Tonal).
- Abweichungen, die bewusst eigen bleiben: eigene Icons und Szenen, ein eigener Akzent erst in
/replica-brand, eigene Texte. Die Kartenformen sind M3-Expressive-Standardformen (MaterialShapes: Cookie, Circle, Triangle, Wavy), damit ist nichts vom Original nachgezeichnet.