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,110 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../models/emergency_number.dart';
|
||||
import '../../../models/emergency_type.dart';
|
||||
import '../../../services/dialer_service.dart';
|
||||
|
||||
/// Großer, gut antippbarer Button für eine einzelne [EmergencyNumber].
|
||||
///
|
||||
/// Löst den Anruf direkt über [DialerService] aus – dafür ist kein
|
||||
/// Callback nach oben nötig, da der Button keine weitere UI-Logik
|
||||
/// beeinflusst. Kann der Wähler nicht geöffnet werden, zeigt der Button
|
||||
/// die Nummer als einfachen Fallback in einer [SnackBar] an.
|
||||
class EmergencyButton extends StatelessWidget {
|
||||
const EmergencyButton({
|
||||
super.key,
|
||||
required this.emergencyNumber,
|
||||
this.dialerService = const DialerService(),
|
||||
});
|
||||
|
||||
final EmergencyNumber emergencyNumber;
|
||||
final DialerService dialerService;
|
||||
|
||||
IconData get _icon {
|
||||
switch (emergencyNumber.type) {
|
||||
case EmergencyType.general:
|
||||
return Icons.emergency;
|
||||
case EmergencyType.police:
|
||||
return Icons.local_police;
|
||||
case EmergencyType.fire:
|
||||
return Icons.local_fire_department;
|
||||
case EmergencyType.ambulance:
|
||||
return Icons.local_hospital;
|
||||
case EmergencyType.seaRescue:
|
||||
return Icons.directions_boat;
|
||||
case EmergencyType.mountainRescue:
|
||||
return Icons.terrain;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onTap(BuildContext context) async {
|
||||
final success = await dialerService.call(emergencyNumber.number);
|
||||
if (!success && context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(emergencyNumber.number)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wählt `labelDe`/`labelEn` (AP1-Datenfeld, keine ARB-Übersetzung – die
|
||||
/// Notrufnummern-Datenbasis kennt bewusst nur diese zwei Sprachen, siehe
|
||||
/// `docs/plan.md` Abschnitt 4) passend zur aktuellen App-Locale aus.
|
||||
String _localizedNumberLabel(BuildContext context) {
|
||||
final languageCode = Localizations.localeOf(context).languageCode;
|
||||
return languageCode == 'de' ? emergencyNumber.labelDe : emergencyNumber.labelEn;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final label = _localizedNumberLabel(context);
|
||||
final semanticLabel = AppLocalizations.of(
|
||||
context,
|
||||
)!.emergencyButtonSemanticLabel(label, emergencyNumber.number);
|
||||
|
||||
return Semantics(
|
||||
button: true,
|
||||
label: semanticLabel,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: 96,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => _onTap(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Tooltip(
|
||||
message: semanticLabel,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(_icon, size: 40),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
Text(
|
||||
emergencyNumber.number,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user