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:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user