8.6 KiB
8.6 KiB
Architecture: Wetter-Klon (Android, ohne Google)
Basis: recon.md, features.csv. Schwerpunkt: modernes Design und Homescreen-Widgets.
Es gibt keinen Server, keine Accounts und keine Zahlungen. Die App läuft komplett auf dem Gerät und spricht nur öffentliche, schlüsselfreie APIs an.
Stack
| Schicht | Wahl | warum |
|---|---|---|
| Sprache/UI | Kotlin + Jetpack Compose, Material 3 Expressive | native Animationen, Shape-Morphing, Dynamic Color: genau der Look des Originals |
| Hintergründe | Compose Canvas + AGSL Runtime Shaders (API 33+), Fallback auf Canvas-Partikel | flüssiger Regen/Schnee/Wolken/Sonne bei 60–120 fps, eigene Grafik statt Google-Assets |
| Widgets | Jetpack Glance (+ RemoteViews nur wo nötig) | Compose-artige Widget-API, responsive Größen, Dynamic Color |
| Persistenz | Room (SQLite) + DataStore | eine lokale DB, offline-first |
| Netzwerk | Ktor Client + kotlinx.serialization | leicht, keine Google-Abhängigkeit |
| Hintergrundjobs | WorkManager | Refresh, Warnungen, Widget-Updates ohne Play Services |
| Standort | android.location.LocationManager (kein Fused Provider) |
funktioniert ohne GMS (GrapheneOS, /e/, LineageOS) |
| Karte | MapLibre Native + OSM-/OpenFreeMap-Tiles, RainViewer-Radarkacheln | Open Source, keine Google Maps |
| DI | Hilt oder manuell (Koin) | Koin: weniger Magie, reicht für eine App |
| Build/Verteilung | Gradle KTS, minSdk 29, targetSdk aktuell, F-Droid-tauglich (keine proprietären Libs) |
Datenquellen (offiziell, öffentlich)
| Zweck | API | Hinweise |
|---|---|---|
| Vorhersage aktuell/stündlich/10 Tage | Open-Meteo /v1/forecast (models=best_match, für DE icon_seamless) |
kostenlos nichtkommerziell, CC BY 4.0, Attribution in den Einstellungen |
| Minutengenauer Niederschlag | Open-Meteo minutely_15 |
Basis für „Regen in 20 Min“ |
| Luftqualität + Pollen | Open-Meteo Air Quality API | Pollen nur in Europa |
| Ortssuche | Open-Meteo Geocoding API | Name/PLZ |
| Reverse Geocoding (GPS → Name) | Nominatim (OSM), max. 1 Req/s, eigener User-Agent | nur beim Standortwechsel |
| Warnungen DE | DWD Warnungen (warnings.json/CAP) über Bright Sky API |
|
| Warnungen EU | MeteoAlarm CAP/Atom Feeds | |
| Radar | RainViewer Weather Maps API (Vergangenheit + Nowcast) | Attribution Pflicht |
Schema
Siehe schema.sql: 6 Tabellen (locations, card_layout, forecast_cache, alerts, widget_config, notification_pref), die Einstellungen liegen in DataStore.
Zugriffsregeln: Es gibt keinen Mehrbenutzerbetrieb, Row Level Security entfällt. Die Daten liegen app-privat im Sandbox-Speicher, Backup über Auto Backup ist optional (ausschaltbar).
Harte Constraints: nur ein is_current-Ort (partieller Unique-Index), keine doppelten Orte (gerundete Koordinaten), Warnungen werden über die Provider-ID dedupliziert.
Interne „API“ (Repositories / Use Cases)
| Aufruf | macht | Input | Output | Flow |
|---|---|---|---|---|
ForecastRepo.observe(locId) |
Flow aus Cache, löst Refresh aus, wenn älter als 30 min | locId | Forecast + Status (fresh/stale/offline) |
F01 |
ForecastRepo.refresh(locId, force) |
Open-Meteo forecast + air laden, Cache schreiben | locId | Result | F01 |
LocationRepo.updateCurrent() |
GPS → Reverse Geocoding → is_current-Zeile |
– | Location | F01 |
LocationRepo.search(q) |
Geocoding, entprellt 300 ms | query | List | F02 |
LocationRepo.add/delete/reorder |
CRUD + Standard-card_layout anlegen |
Place / id / order | – | F02, F03, F04 |
LayoutRepo.move(locId, card, toPos) |
Kartenreihenfolge pro Stadt | – | – | F07 |
AlertRepo.sync(locId) |
DWD/MeteoAlarm abrufen, abgelaufene löschen | locId | List | F08 |
RadarRepo.frames() |
RainViewer-Frame-Liste (−2 h … +30 min) | – | Frames | F05 |
BriefGenerator.build(forecast, alerts) |
regelbasierter Satz („Ab 15 Uhr Regen, morgen 8° kühler“) | Forecast | String | S01 |
SettingsRepo |
Einheiten, Theme, Animationen | – | Flow | F06 |
Hintergrundjobs (WorkManager)
| Job | Takt | macht |
|---|---|---|
RefreshWorker |
periodisch 30 min (Netz vorhanden), Batterie nicht niedrig | alle Orte + Widgets aktualisieren |
AlertWorker |
15 min | Warnungen abrufen, neue severe/extreme → Notification |
RainSoonWorker |
15 min, nur Orte mit rain_alerts |
minutely_15 prüfen → „Regen in ~X Min“ |
TomorrowWorker |
täglich zur eingestellten Uhrzeit | Morgen-Vorhersage als Notification |
| Widget-Update | nach jedem Refresh + updatePeriodMillis als Fallback |
GlanceAppWidget.updateAll() |
Design-Architektur (Priorität)
- Theme: Material 3 Expressive, Dynamic Color (Monet) plus eine eigene, zur Wetterlage passende Farbpalette (z. B. klar/Tag → Blau-Gelb, Gewitter → Violett-Grau).
WeatherThemeliefert Tokens ausreplica-design. - Hintergrund-Engine:
WeatherScene(condition, isDay, intensity, windDir)→ AGSL-Shader-Layer (Himmelsverlauf, Wolken, Niederschlagspartikel, Blitz, Nebel), mit Parallax beim Scrollen. Bei aktiviertem Battery Saver bzw. „Animationen reduzieren“ wird ein statischer Verlauf gezeigt. - Karten: wiederverwendbare
MetricCardmit expressiven Formen (Cookie-/Pill-Shapes), eigene Gauges (UV-Bogen, Windkompass, Sonnenbogen, AQI-Skala) in Canvas, alles eigene Icons (z. B. Material Symbols, Apache 2.0, plus eigene Wettericons). - Motion: Shared-Element-Übergang von der Städteliste zur Stadt, Kartendrag mit Spring-Animationen, Haptik beim Einrasten.
- Edge-to-Edge, prädiktive Zurück-Geste, Two-Pane-Layout ab Breite „medium“ (Tablet/Foldable).
Widgets (Priorität)
| Widget | Größen | Inhalt |
|---|---|---|
| Jetzt | 2×1, 2×2 | Icon, Temperatur, H/T, Ort |
| Stündlich | 4×2 | Jetzt + 5–6 Stunden |
| Täglich | 4×2, 4×3 | Jetzt + 5 Tage mit Temperaturbalken |
| Groß/Komplett | 4×4 | Jetzt, stündlich, täglich, Warnhinweis |
| Pille/Glance | 4×1 | Datum + Wetter in einer Zeile (eigener At-a-Glance-Ersatz) |
- Responsive
SizeMode.Responsive, ein Widget-Typ pro Inhalt mit Größen-Breakpoints. - Stile: Dynamic Color, Wetterlage als Hintergrund (vorgerenderte Bitmaps, weil Widgets keine Shader können), transparent.
- Konfigurations-Activity: Ort wählen (oder „aktueller Standort“) und den Stil, mit Live-Vorschau.
- Tippen öffnet direkt die jeweilige Stadt, das Refresh-Icon stößt
RefreshWorkeran.
Was beißt
- Zeitzonen/DST: Stunden und Tage immer in der Zeitzone des Orts (
timezone=auto) zeigen, nicht in der des Geräts. - Doze/Akkuoptimierung: WorkManager-Takte sind nicht garantiert. Bei OEMs mit aggressivem Energiesparen auf die Ausnahme hinweisen.
- Ohne Play Services: Kein Fused Location. Für schnelle Ergebnisse
getCurrentLocationdes Netzwerk-Providers mit Timeout nutzen, sonst die letzte bekannte Position. - Rate Limits: Open-Meteo erlaubt 10k Aufrufe am Tag, kein Problem. Nominatim erlaubt 1 Req/s, also cachen. RainViewer-Tiles müssen gecacht werden.
- Widget-Grenzen: RemoteViews können keine Animationen und keine Shader, daher Hintergründe vorrendern. Updates sind limitiert, also ereignisgesteuert aktualisieren.
- Offline: Der Cache wird immer angezeigt, mit dem Stand „vor X Min“. Ab 3 h wird er als veraltet markiert.
- Lizenz/Attribution: Open-Meteo, DWD, RainViewer und OSM kommen in die About-Seite und ins Kartenoverlay.
- Performance: Shader auf alten Geräten drosseln (adaptive Qualität), Hintergrund pausieren, wenn er nicht sichtbar ist.
- DSGVO: Es gibt kein Tracking und kein Analytics. Koordinaten gehen nur an die Wetter-APIs, auf 2 Nachkommastellen gerundet.
Build-Reihenfolge
- Vertical Slice (S01, S14): GPS → Open-Meteo → Room → Home mit Hero, stündlicher Leiste und 10-Tage-Liste, schlicht gestaltet. Tabellen
locations,forecast_cache. Beweist den Stack ohne GMS. - Design-Fundament (S01): Theme,
WeatherScene-Shader für die 6 Grundlagen (klar, bewölkt, Regen, Schnee, Gewitter, Nebel × Tag/Nacht),MetricCardund alle Must-Karten. - Widgets (S12): Jetzt, Stündlich, Täglich, Konfiguration,
RefreshWorker. Tabellewidget_config. - Orte (S02, S03): Suche, Hinzufügen, Swipe-to-Delete, Pager zwischen Städten.
- Warnungen (S11, S13): DWD/MeteoAlarm, Banner,
AlertWorker. Tabellealerts. - Einstellungen (S07–S09): Einheiten, Theme, Animationen.
- Should: Radar (S06), Kartenreihenfolge (S10,
card_layout), AQI, Druck, Sicht, Detailansichten (S04, S05), großes Widget und Pillen-Widget, Regen-Benachrichtigung. - Could: Brief, Pollen, Morgen-Benachrichtigung, Vibrationen, Tablet-Layout.
- Fixes aus
/replica-entrepreneur.