Files
emergency/lib/repositories/emergency_number_repository.dart
rootandClaude Sonnet 5 e3aa088bc2 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>
2026-07-24 11:29:38 +02:00

74 lines
2.6 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
import '../models/country.dart';
/// Lädt und cacht die statische Notrufnummern-Datenbasis aus
/// `assets/data/emergency_numbers.json`.
///
/// Die Datei wird nur beim ersten [load]-Aufruf eingelesen und geparst;
/// danach liefert [lookup] aus dem In-Memory-Cache.
class EmergencyNumberRepository {
EmergencyNumberRepository({this.assetPath = 'assets/data/emergency_numbers.json'});
final String assetPath;
Map<String, Country>? _countriesByIsoCode;
/// True, sobald [load] erfolgreich durchgelaufen ist.
bool get isLoaded => _countriesByIsoCode != null;
/// Liest und parst die JSON-Datei einmalig ein.
///
/// Wird [load] mehrfach aufgerufen, geschieht nach dem ersten
/// erfolgreichen Durchlauf nichts mehr (Cache bleibt bestehen).
///
/// Wirft eine [FormatException], wenn das JSON fehlerhaft ist das ist
/// ein Programmierfehler (kaputtes Asset) und soll beim Start auffallen,
/// nicht still verschluckt werden.
Future<void> load() async {
if (isLoaded) return;
final raw = await rootBundle.loadString(assetPath);
final decoded = jsonDecode(raw);
if (decoded is! Map<String, dynamic>) {
throw const FormatException(
'emergency_numbers.json: erwartetes Top-Level-Objekt fehlt',
);
}
final parsed = <String, Country>{};
for (final entry in decoded.entries) {
final isoCode = entry.key.toUpperCase();
parsed[isoCode] = Country.fromJson(isoCode, entry.value as Map<String, dynamic>);
}
_countriesByIsoCode = parsed;
}
/// Sucht ein Land anhand seines ISO 3166-1 alpha-2 Codes (case-insensitive).
///
/// Gibt `null` zurück, wenn [load] noch nicht aufgerufen wurde oder das
/// Land nicht in der Datenbasis vorhanden ist bewusst keine Exception,
/// damit Aufrufer den Fallback-Pfad (z. B. globaler 112/911-Button) ohne
/// try/catch abbilden können.
Country? lookup(String isoCode) {
final countries = _countriesByIsoCode;
if (countries == null) return null;
return countries[isoCode.toUpperCase()];
}
/// Alle Länder der Datenbasis, alphabetisch nach [Country.nameDe] sortiert
/// (`docs/plan.md`, Abschnitt 8, AP6: Grundlage für den `CountryPickerScreen`).
///
/// Liefert eine leere Liste, wenn [load] noch nicht (erfolgreich)
/// durchgelaufen ist bewusst kein Fehler, analog zu [lookup].
List<Country> get allCountries {
final countries = _countriesByIsoCode;
if (countries == null) return const [];
final sorted = countries.values.toList()..sort((a, b) => a.nameDe.compareTo(b.nameDe));
return sorted;
}
}