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
View File
+56
View File
@@ -0,0 +1,56 @@
import 'emergency_number.dart';
/// Ein Land mit seinen landesspezifischen Notrufnummern.
class Country {
const Country({
required this.isoCode,
required this.nameDe,
required this.nameEn,
required this.flag,
required this.numbers,
});
/// ISO 3166-1 alpha-2 Code, z. B. "DE".
final String isoCode;
final String nameDe;
final String nameEn;
final String flag;
final List<EmergencyNumber> numbers;
factory Country.fromJson(String isoCode, Map<String, dynamic> json) {
final numbersJson = json['numbers'] as List<dynamic>;
return Country(
isoCode: isoCode,
nameDe: json['name_de'] as String,
nameEn: json['name_en'] as String,
flag: json['flag'] as String,
numbers: numbersJson
.map((e) => EmergencyNumber.fromJson(e as Map<String, dynamic>))
.toList(growable: false),
);
}
@override
String toString() => 'Country(isoCode: $isoCode, nameEn: $nameEn)';
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is Country &&
other.isoCode == isoCode &&
other.nameDe == nameDe &&
other.nameEn == nameEn &&
other.flag == flag &&
_listEquals(other.numbers, numbers));
@override
int get hashCode => Object.hash(isoCode, nameDe, nameEn, flag, Object.hashAll(numbers));
static bool _listEquals(List<EmergencyNumber> a, List<EmergencyNumber> b) {
if (a.length != b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
}
+40
View File
@@ -0,0 +1,40 @@
import 'emergency_type.dart';
/// Eine einzelne Notrufnummer eines Landes (z. B. Polizei, Feuerwehr).
class EmergencyNumber {
const EmergencyNumber({
required this.type,
required this.number,
required this.labelDe,
required this.labelEn,
});
final EmergencyType type;
final String number;
final String labelDe;
final String labelEn;
factory EmergencyNumber.fromJson(Map<String, dynamic> json) {
return EmergencyNumber(
type: EmergencyType.fromJson(json['type'] as String),
number: json['number'] as String,
labelDe: json['label_de'] as String,
labelEn: json['label_en'] as String,
);
}
@override
String toString() => 'EmergencyNumber(type: $type, number: $number)';
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is EmergencyNumber &&
other.type == type &&
other.number == number &&
other.labelDe == labelDe &&
other.labelEn == labelEn);
@override
int get hashCode => Object.hash(type, number, labelDe, labelEn);
}
+50
View File
@@ -0,0 +1,50 @@
/// Kategorie eines Notrufs, bestimmt Icon/Farbe/Priorität im UI.
enum EmergencyType {
general,
police,
fire,
ambulance,
seaRescue,
mountainRescue;
/// Wandelt den `type`-String aus `emergency_numbers.json` in den Enum-Wert um.
///
/// Wirft eine [FormatException], wenn der Wert unbekannt ist, damit
/// fehlerhafte Datensätze beim Laden auffallen statt still ignoriert zu werden.
static EmergencyType fromJson(String value) {
switch (value) {
case 'general':
return EmergencyType.general;
case 'police':
return EmergencyType.police;
case 'fire':
return EmergencyType.fire;
case 'ambulance':
return EmergencyType.ambulance;
case 'sea_rescue':
return EmergencyType.seaRescue;
case 'mountain_rescue':
return EmergencyType.mountainRescue;
default:
throw FormatException('Unbekannter EmergencyType: $value');
}
}
/// Wandelt den Enum-Wert zurück in den JSON-String (z. B. für Tests/Debugging).
String toJson() {
switch (this) {
case EmergencyType.general:
return 'general';
case EmergencyType.police:
return 'police';
case EmergencyType.fire:
return 'fire';
case EmergencyType.ambulance:
return 'ambulance';
case EmergencyType.seaRescue:
return 'sea_rescue';
case EmergencyType.mountainRescue:
return 'mountain_rescue';
}
}
}