Files
NoGooleApps/replica/design/components.md
T

12 KiB
Raw Blame History

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 (card bzw. 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
  • 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.