Notrufnummern-Datenbasis, Ländererkennung, State-Management und Lokalisierung (AP1-AP7)

Implementiert den kompletten Kern-Flow der Emergency App gemäß docs/plan.md:
- Notrufnummern-Datenbasis für 199 Länder + Modelle/Repository (AP1)
- DialerService für tel:-Notrufe ohne Auto-Dial (AP2)
- Statisches UI mit Panik-Button-Fallback (AP3)
- Priorisierte Ländererkennung: SIM/Netz -> GPS/Geocoding -> Cache (AP4)
- EmergencyProvider verdrahtet Repository/LocationService mit der UI (AP5)
- Manuelle Länderauswahl als Fallback samt eigener Priorität (AP6)
- UI-Lokalisierung (de/en/fr/es), an erkanntes Land gekoppelt (AP7)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
root
2026-07-24 11:29:38 +02:00
co-authored by Claude Sonnet 5
parent 40e95cc495
commit e3aa088bc2
54 changed files with 7550 additions and 145 deletions
+70
View File
@@ -0,0 +1,70 @@
import 'country_code_sources/cached_country_code_source.dart';
import 'country_code_sources/country_code_source.dart';
import 'country_code_sources/gps_country_code_source.dart';
import 'country_code_sources/manual_country_code_source.dart';
import 'country_code_sources/sim_country_code_source.dart';
/// Orchestriert die priorisierte Ermittlungskette für den aktuellen
/// Ländercode (`docs/plan.md`, Abschnitt 6 + 8, AP4 + AP6):
///
/// 0. manuelle Auswahl des Nutzers (`shared_preferences`, übersteuert alles)
/// 1. SIM/Netz-Ländercode (offline, primär)
/// 2. GPS + Reverse-Geocoding (Fallback, ggf. Netz nötig)
/// 3. zuletzt gespeicherter Code (`shared_preferences`)
///
/// Die erste Quelle, die einen nicht-`null`-Wert liefert, gewinnt; die
/// übrigen Quellen werden dann nicht mehr angefragt. Nach einem Treffer über
/// SIM oder GPS wird der Cache best-effort aktualisiert (Fehler dabei
/// beeinflussen die Rückgabe nicht), damit ein späterer Aufruf ohne
/// Netz/GPS/SIM trotzdem einen aktuellen Wert liefern kann. Die manuelle
/// Auswahl (Stufe 0) wird bewusst **nicht** in diesen automatischen Cache
/// (Stufe 3) geschrieben beides sind getrennte Mechanismen mit eigenem
/// `shared_preferences`-Key, siehe `ManualCountryCodeSource` und
/// `CachedCountryCodeSource`.
///
/// `null` wird nur zurückgegeben, wenn wirklich alle Quellen fehlschlagen
/// die UI (AP5+) muss diesen Fall (`status = countryUnknown`) explizit
/// behandeln.
class LocationService {
LocationService({
CountryCodeSource? simSource,
CountryCodeSource? gpsSource,
CountryCodeCache? cacheSource,
ManualCountryCodeStore? manualSource,
}) : _simSource = simSource ?? const SimCountryCodeSource(),
_gpsSource = gpsSource ?? GpsCountryCodeSource(),
_cacheSource = cacheSource ?? const CachedCountryCodeSource(),
_manualSource = manualSource ?? const ManualCountryCodeSource();
final CountryCodeSource _simSource;
final CountryCodeSource _gpsSource;
final CountryCodeCache _cacheSource;
final ManualCountryCodeStore _manualSource;
Future<String?> resolveCountryCode() async {
final manualResult = await _manualSource.resolve();
if (manualResult != null) {
return manualResult;
}
final simResult = await _simSource.resolve();
if (simResult != null) {
await _cacheSource.save(simResult);
return simResult;
}
final gpsResult = await _gpsSource.resolve();
if (gpsResult != null) {
await _cacheSource.save(gpsResult);
return gpsResult;
}
return _cacheSource.resolve();
}
/// Setzt oder löscht die manuelle Länderauswahl (`docs/plan.md`,
/// Abschnitt 8, AP6). `isoCode == null` löscht eine zuvor gesetzte Auswahl
/// wieder, sodass der nächste [resolveCountryCode]-Aufruf wieder auf die
/// automatische Kette (SIM → GPS → Cache) zurückfällt.
Future<void> setManualCountryCode(String? isoCode) => _manualSource.save(isoCode);
}