From 98cda8c976c6a71c7581a23abe6c2a225ad7d84d Mon Sep 17 00:00:00 2001 From: Janez T Date: Thu, 23 Oct 2025 19:17:13 +0200 Subject: [PATCH] feat: Enhance SAR message handling with color indexing and localization - Added `sarColorIndex` to `Message` and `SarMarker` models to support color indexing for SAR markers. - Introduced a standard color palette in `SarTemplate` and methods to retrieve colors based on index. - Updated `SarTemplate` to include localization for template names. - Modified `SarUpdateSheet` and message sending logic to include color index in SAR messages. - Enhanced `SarMessageParser` to support both old and new message formats with color index. - Updated UI components to reflect changes in SAR marker color handling based on the new color index. - Improved sample data generation to utilize localized strings for better testing and demonstration. --- .claude/settings.local.json | 3 +- lib/l10n/app_de.arb | 80 ++++- lib/l10n/app_en.arb | 279 +++++++++++++++ lib/l10n/app_es.arb | 80 ++++- lib/l10n/app_fr.arb | 80 ++++- lib/l10n/app_hr.arb | 82 ++++- lib/l10n/app_it.arb | 80 ++++- lib/l10n/app_localizations.dart | 323 ++++++++++++++++++ lib/l10n/app_localizations_de.dart | 201 ++++++++++- lib/l10n/app_localizations_en.dart | 169 +++++++++ lib/l10n/app_localizations_es.dart | 207 ++++++++++- lib/l10n/app_localizations_fr.dart | 205 ++++++++++- lib/l10n/app_localizations_hr.dart | 200 ++++++++++- lib/l10n/app_localizations_it.dart | 203 ++++++++++- lib/l10n/app_localizations_sl.dart | 201 ++++++++++- lib/l10n/app_sl.arb | 82 ++++- lib/models/message.dart | 5 + lib/models/sar_marker.dart | 4 + lib/models/sar_template.dart | 160 +++++++-- lib/screens/map_tab.dart | 9 +- lib/screens/messages_tab.dart | 121 ++++++- .../sar_template_management_screen.dart | 6 +- lib/screens/settings_screen.dart | 6 + lib/utils/sample_data_generator.dart | 104 +++--- lib/utils/sar_message_parser.dart | 81 ++++- .../contacts/direct_message_sheet.dart | 10 + lib/widgets/map_markers.dart | 17 +- lib/widgets/messages/sar_update_sheet.dart | 6 +- 28 files changed, 2734 insertions(+), 270 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5a714f0..3fedfd9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -30,7 +30,8 @@ "Bash(git --no-pager diff:*)", "Bash(git add:*)", "Bash(git commit -m \"$(cat <<''EOF''\nfeat: Add Linux desktop build support to CI/CD workflow\n\nAdd build-linux job to compile Linux x64 desktop application and\nintegrate it into the R2 upload and release workflows.\n\nChanges:\n- New build-linux job: Builds Flutter Linux desktop app with GTK-3\n- Archives Linux build as tar.gz for distribution\n- Added Linux artifact download in upload-to-r2 job\n- Updated artifact preparation to copy Linux archives\n- Added Linux download card (🐧) to generated index.html\n- Included Linux artifacts in GitHub releases\n- Added Linux to download summary in workflow output\n\nThe Linux build produces MeshCore-SAR-Linux.tar.gz containing the\ncompiled application bundle ready for x64 Linux systems.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude \nEOF\n)\")", - "Bash(git --no-pager log -1 --stat)" + "Bash(git --no-pager log -1 --stat)", + "Bash(awk:*)" ], "deny": [], "ask": [] diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 425127b..6c74161 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1752,6 +1752,10 @@ "textCopiedToClipboard": "Text in Zwischenablage kopiert", "deleteMessage": "Nachricht löschen", "deleteMessageConfirmation": "Möchten Sie diese Nachricht wirklich löschen?", + "shareLocation": "Standort teilen", + "shareLocationText": "{markerInfo}\n\nKoordinaten: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "SAR Standort", + "locationShared": "Standort geteilt", "refreshedContacts": "Kontakte aktualisiert", "@refreshedContacts": { @@ -2326,12 +2330,12 @@ } }, - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", + "sarTemplates": "SAR-Vorlagen", + "manageSarTemplates": "SAR-Vorlagen verwalten", + "addTemplate": "Vorlage hinzufügen", + "editTemplate": "Vorlage bearbeiten", + "deleteTemplate": "Vorlage löschen", + "templateName": "Vorlagenname", "templateNameHint": "e.g. Found Person", "templateEmoji": "Emoji", "emojiRequired": "Emoji ist erforderlich", @@ -2340,8 +2344,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Importieren", + "exportToClipboard": "Exportieren", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -2350,10 +2354,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Auf Standard zurücksetzen", + "resetToDefaultsConfirmation": "Dadurch werden alle benutzerdefinierten Vorlagen gelöscht und die 4 Standardvorlagen wiederhergestellt. Fortfahren?", + "reset": "Zurücksetzen", + "resetComplete": "Vorlagen auf Standard zurückgesetzt", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -2382,5 +2386,55 @@ "noContactsOrRoomsAvailable": "Keine Kontakte oder Räume verfügbar", "messagesWillBeSentToPublicChannel": "Nachrichten werden an öffentlichen Kanal gesendet", "newMessage": "Neue Nachricht", - "channel": "Kanal" + "channel": "Kanal", + + "samplePoliceLead": "Polizeiführer", + "sampleDroneOperator": "Drohnenbediener", + "sampleFirefighterAlpha": "Feuerwehrmann", + "sampleMedicCharlie": "Sanitäter", + "sampleCommandDelta": "Kommando", + "sampleFireEngine": "Feuerwehrfahrzeug", + "sampleAirSupport": "Luftunterstützung", + "sampleBaseCoordinator": "Basiskoordinator", + "channelEmergency": "Notfall", + "channelCoordination": "Koordination", + "channelUpdates": "Aktualisierungen", + "sampleTeamMember": "Beispiel-Teammitglied", + "sampleScout": "Beispiel-Späher", + "sampleBase": "Beispiel-Basis", + "sampleSearcher": "Beispiel-Sucher", + "sampleObjectBackpack": " Rucksack gefunden - blaue Farbe", + "sampleObjectVehicle": " Fahrzeug verlassen - Besitzer prüfen", + "sampleObjectCamping": " Campingausrüstung entdeckt", + "sampleObjectTrailMarker": " Wegmarkierung abseits des Pfades gefunden", + "sampleMsgAllTeamsCheckIn": "Alle Teams melden", + "sampleMsgWeatherUpdate": "Wetterupdate: Klarer Himmel, Temp. 18°C", + "sampleMsgBaseCamp": "Basislager am Sammelplatz eingerichtet", + "sampleMsgTeamAlpha": "Team bewegt sich zu Sektor 2", + "sampleMsgRadioCheck": "Funkcheck - alle Stationen antworten", + "sampleMsgWaterSupply": "Wasserversorgung verfügbar an Kontrollpunkt 3", + "sampleMsgTeamBravo": "Team meldet: Sektor 1 frei", + "sampleMsgEtaRallyPoint": "Ankunftszeit am Sammelpunkt: 15 Minuten", + "sampleMsgSupplyDrop": "Versorgungsabwurf bestätigt für 14:00", + "sampleMsgDroneSurvey": "Drohnenüberwachung abgeschlossen - keine Funde", + "sampleMsgTeamCharlie": "Team fordert Unterstützung an", + "sampleMsgRadioDiscipline": "An alle Einheiten: Funkdisziplin wahren", + "sampleMsgUrgentMedical": "DRINGEND: Medizinische Hilfe benötigt in Sektor 4", + "sampleMsgAdultMale": " Erwachsener Mann, bei Bewusstsein", + "sampleMsgFireSpotted": "Feuer gesichtet - Koordinaten folgen", + "sampleMsgSpreadingRapidly": " Breitet sich schnell aus!", + "sampleMsgPriorityHelicopter": "PRIORITÄT: Brauche Hubschrauberunterstützung", + "sampleMsgMedicalTeamEnRoute": "Medizinisches Team auf dem Weg zu Ihrem Standort", + "sampleMsgEvacHelicopter": "Evakuierungshubschrauber ETA 10 Minuten", + "sampleMsgEmergencyResolved": "Notfall behoben - alles klar", + "sampleMsgEmergencyStagingArea": " Notfall-Sammelplatz", + "sampleMsgEmergencyServices": "Rettungsdienste benachrichtigt und auf dem Weg", + "sampleAlphaTeamLead": "Team-Leiter", + "sampleBravoScout": "Späher", + "sampleCharlieMedic": "Sanitäter", + "sampleDeltaNavigator": "Navigator", + "sampleEchoSupport": "Unterstützung", + "sampleBaseCommand": "Basis-Kommando", + "sampleFieldCoordinator": "Feldkoordinator", + "sampleMedicalTeam": "Medizinisches Team" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a89b50e..9c3d41f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1768,6 +1768,40 @@ "description": "Confirmation text for message deletion" }, + "shareLocation": "Share location", + "@shareLocation": { + "description": "Option to share SAR marker location" + }, + + "shareLocationText": "{markerInfo}\n\nCoordinates: {lat}, {lon}\n\nGoogle Maps: {url}", + "@shareLocationText": { + "description": "Formatted text for sharing SAR marker location", + "placeholders": { + "markerInfo": { + "type": "String" + }, + "lat": { + "type": "String" + }, + "lon": { + "type": "String" + }, + "url": { + "type": "String" + } + } + }, + + "sarLocationShare": "SAR Location", + "@sarLocationShare": { + "description": "Subject line when sharing SAR marker location" + }, + + "locationShared": "Location shared", + "@locationShared": { + "description": "Success message when location is shared" + }, + "refreshedContacts": "Refreshed contacts", "@refreshedContacts": { "description": "Success message when contacts are refreshed" @@ -2639,5 +2673,250 @@ "channel": "Channel", "@channel": { "description": "Channel label in notifications" + }, + + "samplePoliceLead": "Police Lead", + "@samplePoliceLead": { + "description": "Sample team member name" + }, + + "sampleDroneOperator": "Drone Operator", + "@sampleDroneOperator": { + "description": "Sample team member name" + }, + + "sampleFirefighterAlpha": "Firefighter", + "@sampleFirefighterAlpha": { + "description": "Sample team member name" + }, + + "sampleMedicCharlie": "Medic", + "@sampleMedicCharlie": { + "description": "Sample team member name" + }, + + "sampleCommandDelta": "Command", + "@sampleCommandDelta": { + "description": "Sample team member name" + }, + + "sampleFireEngine": "Fire Engine", + "@sampleFireEngine": { + "description": "Sample team member name" + }, + + "sampleAirSupport": "Air Support", + "@sampleAirSupport": { + "description": "Sample team member name" + }, + + "sampleBaseCoordinator": "Base Coordinator", + "@sampleBaseCoordinator": { + "description": "Sample team member name" + }, + + "channelEmergency": "Emergency", + "@channelEmergency": { + "description": "Emergency channel name" + }, + + "channelCoordination": "Coordination", + "@channelCoordination": { + "description": "Coordination channel name" + }, + + "channelUpdates": "Updates", + "@channelUpdates": { + "description": "Updates channel name" + }, + + "sampleTeamMember": "Sample Team Member", + "@sampleTeamMember": { + "description": "Sample sender name" + }, + + "sampleScout": "Sample Scout", + "@sampleScout": { + "description": "Sample sender name" + }, + + "sampleBase": "Sample Base", + "@sampleBase": { + "description": "Sample sender name" + }, + + "sampleSearcher": "Sample Searcher", + "@sampleSearcher": { + "description": "Sample sender name" + }, + + "sampleObjectBackpack": " Backpack found - blue color", + "@sampleObjectBackpack": { + "description": "Sample object note" + }, + + "sampleObjectVehicle": " Vehicle abandoned - check for owner", + "@sampleObjectVehicle": { + "description": "Sample object note" + }, + + "sampleObjectCamping": " Camping equipment discovered", + "@sampleObjectCamping": { + "description": "Sample object note" + }, + + "sampleObjectTrailMarker": " Trail marker found off-path", + "@sampleObjectTrailMarker": { + "description": "Sample object note" + }, + + "sampleMsgAllTeamsCheckIn": "All teams check in", + "@sampleMsgAllTeamsCheckIn": { + "description": "Sample channel message" + }, + + "sampleMsgWeatherUpdate": "Weather update: Clear skies, temp 18°C", + "@sampleMsgWeatherUpdate": { + "description": "Sample channel message" + }, + + "sampleMsgBaseCamp": "Base camp established at staging area", + "@sampleMsgBaseCamp": { + "description": "Sample channel message" + }, + + "sampleMsgTeamAlpha": "Team moving to sector 2", + "@sampleMsgTeamAlpha": { + "description": "Sample channel message" + }, + + "sampleMsgRadioCheck": "Radio check - all stations respond", + "@sampleMsgRadioCheck": { + "description": "Sample channel message" + }, + + "sampleMsgWaterSupply": "Water supply available at checkpoint 3", + "@sampleMsgWaterSupply": { + "description": "Sample channel message" + }, + + "sampleMsgTeamBravo": "Team reporting: sector 1 clear", + "@sampleMsgTeamBravo": { + "description": "Sample channel message" + }, + + "sampleMsgEtaRallyPoint": "ETA to rally point: 15 minutes", + "@sampleMsgEtaRallyPoint": { + "description": "Sample channel message" + }, + + "sampleMsgSupplyDrop": "Supply drop confirmed for 14:00", + "@sampleMsgSupplyDrop": { + "description": "Sample channel message" + }, + + "sampleMsgDroneSurvey": "Drone survey completed - no findings", + "@sampleMsgDroneSurvey": { + "description": "Sample channel message" + }, + + "sampleMsgTeamCharlie": "Team requesting backup", + "@sampleMsgTeamCharlie": { + "description": "Sample channel message" + }, + + "sampleMsgRadioDiscipline": "All units: maintain radio discipline", + "@sampleMsgRadioDiscipline": { + "description": "Sample channel message" + }, + + "sampleMsgUrgentMedical": "URGENT: Medical assistance needed at sector 4", + "@sampleMsgUrgentMedical": { + "description": "Sample emergency message" + }, + + "sampleMsgAdultMale": " Adult male, conscious", + "@sampleMsgAdultMale": { + "description": "Sample emergency message note" + }, + + "sampleMsgFireSpotted": "Fire spotted - coordinates incoming", + "@sampleMsgFireSpotted": { + "description": "Sample emergency message" + }, + + "sampleMsgSpreadingRapidly": " Spreading rapidly!", + "@sampleMsgSpreadingRapidly": { + "description": "Sample emergency message note" + }, + + "sampleMsgPriorityHelicopter": "PRIORITY: Need helicopter support", + "@sampleMsgPriorityHelicopter": { + "description": "Sample emergency message" + }, + + "sampleMsgMedicalTeamEnRoute": "Medical team en route to your location", + "@sampleMsgMedicalTeamEnRoute": { + "description": "Sample emergency message" + }, + + "sampleMsgEvacHelicopter": "Evac helicopter ETA 10 minutes", + "@sampleMsgEvacHelicopter": { + "description": "Sample emergency message" + }, + + "sampleMsgEmergencyResolved": "Emergency resolved - all clear", + "@sampleMsgEmergencyResolved": { + "description": "Sample emergency message" + }, + + "sampleMsgEmergencyStagingArea": " Emergency staging area", + "@sampleMsgEmergencyStagingArea": { + "description": "Sample emergency message note" + }, + + "sampleMsgEmergencyServices": "Emergency services notified and responding", + "@sampleMsgEmergencyServices": { + "description": "Sample emergency message" + }, + + "sampleAlphaTeamLead": "Team Lead", + "@sampleAlphaTeamLead": { + "description": "Sample team name" + }, + + "sampleBravoScout": "Scout", + "@sampleBravoScout": { + "description": "Sample team name" + }, + + "sampleCharlieMedic": "Medic", + "@sampleCharlieMedic": { + "description": "Sample team name" + }, + + "sampleDeltaNavigator": "Navigator", + "@sampleDeltaNavigator": { + "description": "Sample team name" + }, + + "sampleEchoSupport": "Support", + "@sampleEchoSupport": { + "description": "Sample team name" + }, + + "sampleBaseCommand": "Base Command", + "@sampleBaseCommand": { + "description": "Sample team name" + }, + + "sampleFieldCoordinator": "Field Coordinator", + "@sampleFieldCoordinator": { + "description": "Sample team name" + }, + + "sampleMedicalTeam": "Medical Team", + "@sampleMedicalTeam": { + "description": "Sample team name" } } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 64fb259..c6e1e2a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1752,6 +1752,10 @@ "textCopiedToClipboard": "Texto copiado al portapapeles", "deleteMessage": "Eliminar mensaje", "deleteMessageConfirmation": "¿Está seguro de que desea eliminar este mensaje?", + "shareLocation": "Compartir ubicación", + "shareLocationText": "{markerInfo}\n\nCoordenadas: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "Ubicación SAR", + "locationShared": "Ubicación compartida", "refreshedContacts": "Contactos actualizados", "@refreshedContacts": { @@ -2321,12 +2325,12 @@ } }, - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", + "sarTemplates": "Plantillas SAR", + "manageSarTemplates": "Gestionar plantillas SAR", + "addTemplate": "Agregar plantilla", + "editTemplate": "Editar plantilla", + "deleteTemplate": "Eliminar plantilla", + "templateName": "Nombre de plantilla", "templateNameHint": "e.g. Found Person", "templateEmoji": "Emoji", "emojiRequired": "Se requiere emoji", @@ -2335,8 +2339,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Importar", + "exportToClipboard": "Exportar", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -2345,10 +2349,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Restablecer valores predeterminados", + "resetToDefaultsConfirmation": "Esto eliminará todas las plantillas personalizadas y restaurará las 4 plantillas predeterminadas. ¿Continuar?", + "reset": "Restablecer", + "resetComplete": "Plantillas restablecidas a valores predeterminados", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -2377,5 +2381,55 @@ "noContactsOrRoomsAvailable": "No hay contactos o salas disponibles", "messagesWillBeSentToPublicChannel": "Los mensajes se enviarán al canal público", "newMessage": "Nuevo mensaje", - "channel": "Canal" + "channel": "Canal", + + "samplePoliceLead": "Jefe de Policía", + "sampleDroneOperator": "Operador de Dron", + "sampleFirefighterAlpha": "Bombero", + "sampleMedicCharlie": "Médico", + "sampleCommandDelta": "Comando", + "sampleFireEngine": "Camión de Bomberos", + "sampleAirSupport": "Apoyo Aéreo", + "sampleBaseCoordinator": "Coordinador de Base", + "channelEmergency": "Emergencia", + "channelCoordination": "Coordinación", + "channelUpdates": "Actualizaciones", + "sampleTeamMember": "Miembro de Equipo de Muestra", + "sampleScout": "Explorador de Muestra", + "sampleBase": "Base de Muestra", + "sampleSearcher": "Buscador de Muestra", + "sampleObjectBackpack": " Mochila encontrada - color azul", + "sampleObjectVehicle": " Vehículo abandonado - verificar propietario", + "sampleObjectCamping": " Equipo de camping descubierto", + "sampleObjectTrailMarker": " Marcador de sendero encontrado fuera del camino", + "sampleMsgAllTeamsCheckIn": "Todos los equipos reporten", + "sampleMsgWeatherUpdate": "Actualización del clima: Cielo despejado, temp 18°C", + "sampleMsgBaseCamp": "Campamento base establecido en área de preparación", + "sampleMsgTeamAlpha": "Equipo moviéndose al sector 2", + "sampleMsgRadioCheck": "Prueba de radio - todas las estaciones respondan", + "sampleMsgWaterSupply": "Suministro de agua disponible en punto de control 3", + "sampleMsgTeamBravo": "Equipo reportando: sector 1 despejado", + "sampleMsgEtaRallyPoint": "ETA al punto de encuentro: 15 minutos", + "sampleMsgSupplyDrop": "Caída de suministros confirmada para las 14:00", + "sampleMsgDroneSurvey": "Inspección con dron completada - sin hallazgos", + "sampleMsgTeamCharlie": "Equipo solicitando apoyo", + "sampleMsgRadioDiscipline": "Todas las unidades: mantener disciplina de radio", + "sampleMsgUrgentMedical": "URGENTE: Asistencia médica necesaria en sector 4", + "sampleMsgAdultMale": " Hombre adulto, consciente", + "sampleMsgFireSpotted": "Fuego avistado - coordenadas próximas", + "sampleMsgSpreadingRapidly": " ¡Se propaga rápidamente!", + "sampleMsgPriorityHelicopter": "PRIORIDAD: Necesitamos apoyo de helicóptero", + "sampleMsgMedicalTeamEnRoute": "Equipo médico en camino a su ubicación", + "sampleMsgEvacHelicopter": "Helicóptero de evacuación ETA 10 minutos", + "sampleMsgEmergencyResolved": "Emergencia resuelta - todo despejado", + "sampleMsgEmergencyStagingArea": " Área de preparación de emergencia", + "sampleMsgEmergencyServices": "Servicios de emergencia notificados y respondiendo", + "sampleAlphaTeamLead": "Líder de Equipo", + "sampleBravoScout": "Explorador", + "sampleCharlieMedic": "Médico", + "sampleDeltaNavigator": "Navegador", + "sampleEchoSupport": "Apoyo", + "sampleBaseCommand": "Comando de Base", + "sampleFieldCoordinator": "Coordinador de Campo", + "sampleMedicalTeam": "Equipo Médico" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2df4a18..baaa18b 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1752,6 +1752,10 @@ "textCopiedToClipboard": "Texte copié dans le presse-papiers", "deleteMessage": "Supprimer le message", "deleteMessageConfirmation": "Êtes-vous sûr de vouloir supprimer ce message?", + "shareLocation": "Partager la position", + "shareLocationText": "{markerInfo}\n\nCoordonnées: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "Position SAR", + "locationShared": "Position partagée", "refreshedContacts": "Contacts actualisés", "@refreshedContacts": { @@ -2326,12 +2330,12 @@ } }, - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", + "sarTemplates": "Modèles SAR", + "manageSarTemplates": "Gérer les modèles SAR", + "addTemplate": "Ajouter un modèle", + "editTemplate": "Modifier le modèle", + "deleteTemplate": "Supprimer le modèle", + "templateName": "Nom du modèle", "templateNameHint": "e.g. Found Person", "templateEmoji": "Emoji", "emojiRequired": "Emoji est requis", @@ -2340,8 +2344,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Importer", + "exportToClipboard": "Exporter", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -2350,10 +2354,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Réinitialiser aux valeurs par défaut", + "resetToDefaultsConfirmation": "Cela supprimera tous les modèles personnalisés et restaurera les 4 modèles par défaut. Continuer?", + "reset": "Réinitialiser", + "resetComplete": "Modèles réinitialisés aux valeurs par défaut", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -2382,5 +2386,55 @@ "noContactsOrRoomsAvailable": "Aucun contact ou salle disponible", "messagesWillBeSentToPublicChannel": "Les messages seront envoyés au canal public", "newMessage": "Nouveau message", - "channel": "Canal" + "channel": "Canal", + + "samplePoliceLead": "Chef de Police", + "sampleDroneOperator": "Opérateur de Drone", + "sampleFirefighterAlpha": "Pompier", + "sampleMedicCharlie": "Médecin", + "sampleCommandDelta": "Commandement", + "sampleFireEngine": "Camion de Pompiers", + "sampleAirSupport": "Soutien Aérien", + "sampleBaseCoordinator": "Coordinateur de Base", + "channelEmergency": "Urgence", + "channelCoordination": "Coordination", + "channelUpdates": "Mises à jour", + "sampleTeamMember": "Membre d'Équipe Exemple", + "sampleScout": "Éclaireur Exemple", + "sampleBase": "Base Exemple", + "sampleSearcher": "Chercheur Exemple", + "sampleObjectBackpack": " Sac à dos trouvé - couleur bleue", + "sampleObjectVehicle": " Véhicule abandonné - vérifier le propriétaire", + "sampleObjectCamping": " Équipement de camping découvert", + "sampleObjectTrailMarker": " Balise de sentier trouvée hors piste", + "sampleMsgAllTeamsCheckIn": "Toutes les équipes se signaler", + "sampleMsgWeatherUpdate": "Mise à jour météo : Ciel dégagé, temp 18°C", + "sampleMsgBaseCamp": "Camp de base établi à la zone de rassemblement", + "sampleMsgTeamAlpha": "Équipe se déplaçant vers le secteur 2", + "sampleMsgRadioCheck": "Test radio - toutes les stations répondent", + "sampleMsgWaterSupply": "Approvisionnement en eau disponible au point de contrôle 3", + "sampleMsgTeamBravo": "Équipe signale : secteur 1 dégagé", + "sampleMsgEtaRallyPoint": "ETA au point de ralliement : 15 minutes", + "sampleMsgSupplyDrop": "Largage de ravitaillement confirmé pour 14h00", + "sampleMsgDroneSurvey": "Surveillance par drone terminée - aucune découverte", + "sampleMsgTeamCharlie": "Équipe demande du renfort", + "sampleMsgRadioDiscipline": "Toutes les unités : maintenir la discipline radio", + "sampleMsgUrgentMedical": "URGENT : Assistance médicale nécessaire au secteur 4", + "sampleMsgAdultMale": " Homme adulte, conscient", + "sampleMsgFireSpotted": "Feu repéré - coordonnées à venir", + "sampleMsgSpreadingRapidly": " Se propage rapidement !", + "sampleMsgPriorityHelicopter": "PRIORITÉ : Besoin de soutien hélicoptère", + "sampleMsgMedicalTeamEnRoute": "Équipe médicale en route vers votre position", + "sampleMsgEvacHelicopter": "Hélicoptère d'évacuation ETA 10 minutes", + "sampleMsgEmergencyResolved": "Urgence résolue - tout est clair", + "sampleMsgEmergencyStagingArea": " Zone de rassemblement d'urgence", + "sampleMsgEmergencyServices": "Services d'urgence notifiés et en réponse", + "sampleAlphaTeamLead": "Chef d'Équipe", + "sampleBravoScout": "Éclaireur", + "sampleCharlieMedic": "Médecin", + "sampleDeltaNavigator": "Navigateur", + "sampleEchoSupport": "Soutien", + "sampleBaseCommand": "Commandement de Base", + "sampleFieldCoordinator": "Coordinateur de Terrain", + "sampleMedicalTeam": "Équipe Médicale" } diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index a149a69..b7d77dc 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -620,6 +620,10 @@ "textCopiedToClipboard": "Tekst kopiran u međuspremnik", "deleteMessage": "Izbriši poruku", "deleteMessageConfirmation": "Jeste li sigurni da želite izbrisati ovu poruku?", + "shareLocation": "Podijeli lokaciju", + "shareLocationText": "{markerInfo}\n\nKoordinate: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "SAR Lokacija", + "locationShared": "Lokacija podijeljena", "refreshedContacts": "Kontakti osvježeni", @@ -790,13 +794,13 @@ "failedToGetLocation": "Neuspjelo dohvaćanje lokacije: {error}", - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", - "templateNameHint": "e.g. Found Person", + "sarTemplates": "SAR predlošci", + "manageSarTemplates": "Upravljanje SAR predlošcima", + "addTemplate": "Dodaj predložak", + "editTemplate": "Uredi predložak", + "deleteTemplate": "Izbriši predložak", + "templateName": "Naziv predloška", + "templateNameHint": "npr. Pronađena osoba", "templateEmoji": "Emoji", "emojiRequired": "Emoji je obavezan", "nameRequired": "Ime je obavezno", @@ -804,8 +808,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Uvezi", + "exportToClipboard": "Izvezi", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -814,10 +818,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Vrati na zadane", + "resetToDefaultsConfirmation": "Ovo će izbrisati sve prilagođene predloške i vratiti 4 zadana predloška. Nastaviti?", + "reset": "Vrati", + "resetComplete": "Predlošci vraćeni na zadane", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -846,5 +850,55 @@ "noContactsOrRoomsAvailable": "Nema dostupnih kontakata ili soba", "messagesWillBeSentToPublicChannel": "Poruke će biti poslane na javni kanal", "newMessage": "Nova poruka", - "channel": "Kanal" + "channel": "Kanal", + + "samplePoliceLead": "Voditelj Policije", + "sampleDroneOperator": "Operater Drona", + "sampleFirefighterAlpha": "Vatrogasac", + "sampleMedicCharlie": "Medičar", + "sampleCommandDelta": "Zapovjedništvo", + "sampleFireEngine": "Vatrogasno Vozilo", + "sampleAirSupport": "Zračna Podrška", + "sampleBaseCoordinator": "Koordinator Baze", + "channelEmergency": "Hitno", + "channelCoordination": "Koordinacija", + "channelUpdates": "Ažuriranja", + "sampleTeamMember": "Primjer Člana Tima", + "sampleScout": "Primjer Izviđača", + "sampleBase": "Primjer Baze", + "sampleSearcher": "Primjer Tragača", + "sampleObjectBackpack": " Pronađen ruksak - plava boja", + "sampleObjectVehicle": " Napušteno vozilo - provjeriti vlasnika", + "sampleObjectCamping": " Otkrivena oprema za kampiranje", + "sampleObjectTrailMarker": " Oznaka staze pronađena izvan puta", + "sampleMsgAllTeamsCheckIn": "Svi timovi se jave", + "sampleMsgWeatherUpdate": "Ažuriranje vremena: Vedro nebo, temp 18°C", + "sampleMsgBaseCamp": "Bazni kamp uspostavljen na okupljalište", + "sampleMsgTeamAlpha": "Tim se kreće prema sektoru 2", + "sampleMsgRadioCheck": "Provjera radija - sve stanice odgovorite", + "sampleMsgWaterSupply": "Opskrba vodom dostupna na kontrolnoj točki 3", + "sampleMsgTeamBravo": "Tim izvještava: sektor 1 čist", + "sampleMsgEtaRallyPoint": "ETA do točke okupljanja: 15 minuta", + "sampleMsgSupplyDrop": "Isporuka zaliha potvrđena za 14:00", + "sampleMsgDroneSurvey": "Nadzor dronom završen - bez nalaza", + "sampleMsgTeamCharlie": "Tim traži pojačanje", + "sampleMsgRadioDiscipline": "Sve jedinice: održavati radio disciplinu", + "sampleMsgUrgentMedical": "HITNO: Potrebna medicinska pomoć u sektoru 4", + "sampleMsgAdultMale": " Odrasli muškarac, pri svijesti", + "sampleMsgFireSpotted": "Uočen požar - koordinate slijede", + "sampleMsgSpreadingRapidly": " Širi se brzo!", + "sampleMsgPriorityHelicopter": "PRIORITET: Potrebna podrška helikoptera", + "sampleMsgMedicalTeamEnRoute": "Medicinski tim na putu do vaše lokacije", + "sampleMsgEvacHelicopter": "Helikopter za evakuaciju ETA 10 minuta", + "sampleMsgEmergencyResolved": "Hitnost riješena - sve čisto", + "sampleMsgEmergencyStagingArea": " Hitno okupljalište", + "sampleMsgEmergencyServices": "Hitne službe obaviještene i odgovaraju", + "sampleAlphaTeamLead": "Voditelj Tima", + "sampleBravoScout": "Izviđač", + "sampleCharlieMedic": "Medičar", + "sampleDeltaNavigator": "Navigator", + "sampleEchoSupport": "Podrška", + "sampleBaseCommand": "Zapovjedništvo Baze", + "sampleFieldCoordinator": "Terenski Koordinator", + "sampleMedicalTeam": "Medicinski Tim" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index a59caa8..f5e3878 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1752,6 +1752,10 @@ "textCopiedToClipboard": "Testo copiato negli appunti", "deleteMessage": "Elimina messaggio", "deleteMessageConfirmation": "Sei sicuro di voler eliminare questo messaggio?", + "shareLocation": "Condividi posizione", + "shareLocationText": "{markerInfo}\n\nCoordinate: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "Posizione SAR", + "locationShared": "Posizione condivisa", "refreshedContacts": "Contatti aggiornati", "@refreshedContacts": { @@ -2326,12 +2330,12 @@ } }, - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", + "sarTemplates": "Modelli SAR", + "manageSarTemplates": "Gestisci modelli SAR", + "addTemplate": "Aggiungi modello", + "editTemplate": "Modifica modello", + "deleteTemplate": "Elimina modello", + "templateName": "Nome modello", "templateNameHint": "e.g. Found Person", "templateEmoji": "Emoji", "emojiRequired": "Emoji è obbligatorio", @@ -2340,8 +2344,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Importa", + "exportToClipboard": "Esporta", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -2350,10 +2354,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Ripristina predefiniti", + "resetToDefaultsConfirmation": "Questo eliminerà tutti i modelli personalizzati e ripristinerà i 4 modelli predefiniti. Continuare?", + "reset": "Ripristina", + "resetComplete": "Modelli ripristinati ai valori predefiniti", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -2382,5 +2386,55 @@ "noContactsOrRoomsAvailable": "Nessun contatto o stanza disponibile", "messagesWillBeSentToPublicChannel": "I messaggi saranno inviati al canale pubblico", "newMessage": "Nuovo messaggio", - "channel": "Canale" + "channel": "Canale", + + "samplePoliceLead": "Capo della Polizia", + "sampleDroneOperator": "Operatore Drone", + "sampleFirefighterAlpha": "Vigile del Fuoco", + "sampleMedicCharlie": "Medico", + "sampleCommandDelta": "Comando", + "sampleFireEngine": "Autopompa", + "sampleAirSupport": "Supporto Aereo", + "sampleBaseCoordinator": "Coordinatore di Base", + "channelEmergency": "Emergenza", + "channelCoordination": "Coordinamento", + "channelUpdates": "Aggiornamenti", + "sampleTeamMember": "Membro del Team di Esempio", + "sampleScout": "Esploratore di Esempio", + "sampleBase": "Base di Esempio", + "sampleSearcher": "Cercatore di Esempio", + "sampleObjectBackpack": " Zaino trovato - colore blu", + "sampleObjectVehicle": " Veicolo abbandonato - controllare il proprietario", + "sampleObjectCamping": " Attrezzatura da campeggio scoperta", + "sampleObjectTrailMarker": " Segnavia trovato fuori sentiero", + "sampleMsgAllTeamsCheckIn": "Tutti i team segnalarsi", + "sampleMsgWeatherUpdate": "Aggiornamento meteo: Cielo sereno, temp 18°C", + "sampleMsgBaseCamp": "Campo base stabilito all'area di raduno", + "sampleMsgTeamAlpha": "Team si sta spostando al settore 2", + "sampleMsgRadioCheck": "Controllo radio - tutte le stazioni rispondano", + "sampleMsgWaterSupply": "Rifornimento idrico disponibile al punto di controllo 3", + "sampleMsgTeamBravo": "Team segnala: settore 1 libero", + "sampleMsgEtaRallyPoint": "ETA al punto di raduno: 15 minuti", + "sampleMsgSupplyDrop": "Lancio rifornimenti confermato per le 14:00", + "sampleMsgDroneSurvey": "Sorveglianza con drone completata - nessun ritrovamento", + "sampleMsgTeamCharlie": "Team richiede rinforzi", + "sampleMsgRadioDiscipline": "Tutte le unità: mantenere disciplina radio", + "sampleMsgUrgentMedical": "URGENTE: Assistenza medica necessaria al settore 4", + "sampleMsgAdultMale": " Uomo adulto, cosciente", + "sampleMsgFireSpotted": "Incendio avvistato - coordinate in arrivo", + "sampleMsgSpreadingRapidly": " Si sta diffondendo rapidamente!", + "sampleMsgPriorityHelicopter": "PRIORITÀ: Necessario supporto elicottero", + "sampleMsgMedicalTeamEnRoute": "Team medico in rotta verso la vostra posizione", + "sampleMsgEvacHelicopter": "Elicottero di evacuazione ETA 10 minuti", + "sampleMsgEmergencyResolved": "Emergenza risolta - tutto libero", + "sampleMsgEmergencyStagingArea": " Area di raduno di emergenza", + "sampleMsgEmergencyServices": "Servizi di emergenza notificati e in risposta", + "sampleAlphaTeamLead": "Capo Team", + "sampleBravoScout": "Esploratore", + "sampleCharlieMedic": "Medico", + "sampleDeltaNavigator": "Navigatore", + "sampleEchoSupport": "Supporto", + "sampleBaseCommand": "Comando di Base", + "sampleFieldCoordinator": "Coordinatore sul Campo", + "sampleMedicalTeam": "Team Medico" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 4e733bc..f41ef44 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1907,6 +1907,35 @@ abstract class AppLocalizations { /// **'Are you sure you want to delete this message?'** String get deleteMessageConfirmation; + /// Option to share SAR marker location + /// + /// In en, this message translates to: + /// **'Share location'** + String get shareLocation; + + /// Formatted text for sharing SAR marker location + /// + /// In en, this message translates to: + /// **'{markerInfo}\n\nCoordinates: {lat}, {lon}\n\nGoogle Maps: {url}'** + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ); + + /// Subject line when sharing SAR marker location + /// + /// In en, this message translates to: + /// **'SAR Location'** + String get sarLocationShare; + + /// Success message when location is shared + /// + /// In en, this message translates to: + /// **'Location shared'** + String get locationShared; + /// Success message when contacts are refreshed /// /// In en, this message translates to: @@ -2806,6 +2835,300 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Channel'** String get channel; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Police Lead'** + String get samplePoliceLead; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Drone Operator'** + String get sampleDroneOperator; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Firefighter'** + String get sampleFirefighterAlpha; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Medic'** + String get sampleMedicCharlie; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Command'** + String get sampleCommandDelta; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Fire Engine'** + String get sampleFireEngine; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Air Support'** + String get sampleAirSupport; + + /// Sample team member name + /// + /// In en, this message translates to: + /// **'Base Coordinator'** + String get sampleBaseCoordinator; + + /// Emergency channel name + /// + /// In en, this message translates to: + /// **'Emergency'** + String get channelEmergency; + + /// Coordination channel name + /// + /// In en, this message translates to: + /// **'Coordination'** + String get channelCoordination; + + /// Updates channel name + /// + /// In en, this message translates to: + /// **'Updates'** + String get channelUpdates; + + /// Sample sender name + /// + /// In en, this message translates to: + /// **'Sample Team Member'** + String get sampleTeamMember; + + /// Sample sender name + /// + /// In en, this message translates to: + /// **'Sample Scout'** + String get sampleScout; + + /// Sample sender name + /// + /// In en, this message translates to: + /// **'Sample Base'** + String get sampleBase; + + /// Sample sender name + /// + /// In en, this message translates to: + /// **'Sample Searcher'** + String get sampleSearcher; + + /// Sample object note + /// + /// In en, this message translates to: + /// **' Backpack found - blue color'** + String get sampleObjectBackpack; + + /// Sample object note + /// + /// In en, this message translates to: + /// **' Vehicle abandoned - check for owner'** + String get sampleObjectVehicle; + + /// Sample object note + /// + /// In en, this message translates to: + /// **' Camping equipment discovered'** + String get sampleObjectCamping; + + /// Sample object note + /// + /// In en, this message translates to: + /// **' Trail marker found off-path'** + String get sampleObjectTrailMarker; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'All teams check in'** + String get sampleMsgAllTeamsCheckIn; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Weather update: Clear skies, temp 18°C'** + String get sampleMsgWeatherUpdate; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Base camp established at staging area'** + String get sampleMsgBaseCamp; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Team moving to sector 2'** + String get sampleMsgTeamAlpha; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Radio check - all stations respond'** + String get sampleMsgRadioCheck; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Water supply available at checkpoint 3'** + String get sampleMsgWaterSupply; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Team reporting: sector 1 clear'** + String get sampleMsgTeamBravo; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'ETA to rally point: 15 minutes'** + String get sampleMsgEtaRallyPoint; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Supply drop confirmed for 14:00'** + String get sampleMsgSupplyDrop; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Drone survey completed - no findings'** + String get sampleMsgDroneSurvey; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'Team requesting backup'** + String get sampleMsgTeamCharlie; + + /// Sample channel message + /// + /// In en, this message translates to: + /// **'All units: maintain radio discipline'** + String get sampleMsgRadioDiscipline; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'URGENT: Medical assistance needed at sector 4'** + String get sampleMsgUrgentMedical; + + /// Sample emergency message note + /// + /// In en, this message translates to: + /// **' Adult male, conscious'** + String get sampleMsgAdultMale; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'Fire spotted - coordinates incoming'** + String get sampleMsgFireSpotted; + + /// Sample emergency message note + /// + /// In en, this message translates to: + /// **' Spreading rapidly!'** + String get sampleMsgSpreadingRapidly; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'PRIORITY: Need helicopter support'** + String get sampleMsgPriorityHelicopter; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'Medical team en route to your location'** + String get sampleMsgMedicalTeamEnRoute; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'Evac helicopter ETA 10 minutes'** + String get sampleMsgEvacHelicopter; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'Emergency resolved - all clear'** + String get sampleMsgEmergencyResolved; + + /// Sample emergency message note + /// + /// In en, this message translates to: + /// **' Emergency staging area'** + String get sampleMsgEmergencyStagingArea; + + /// Sample emergency message + /// + /// In en, this message translates to: + /// **'Emergency services notified and responding'** + String get sampleMsgEmergencyServices; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Team Lead'** + String get sampleAlphaTeamLead; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Scout'** + String get sampleBravoScout; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Medic'** + String get sampleCharlieMedic; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Navigator'** + String get sampleDeltaNavigator; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Support'** + String get sampleEchoSupport; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Base Command'** + String get sampleBaseCommand; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Field Coordinator'** + String get sampleFieldCoordinator; + + /// Sample team name + /// + /// In en, this message translates to: + /// **'Medical Team'** + String get sampleMedicalTeam; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 24a628f..dab190f 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -1041,6 +1041,25 @@ class AppLocalizationsDe extends AppLocalizations { String get deleteMessageConfirmation => 'Möchten Sie diese Nachricht wirklich löschen?'; + @override + String get shareLocation => 'Standort teilen'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nKoordinaten: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'SAR Standort'; + + @override + String get locationShared => 'Standort geteilt'; + @override String get refreshedContacts => 'Kontakte aktualisiert'; @@ -1379,22 +1398,22 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'SAR-Vorlagen'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'SAR-Vorlagen verwalten'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Vorlage hinzufügen'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Vorlage bearbeiten'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Vorlage löschen'; @override - String get templateName => 'Template Name'; + String get templateName => 'Vorlagenname'; @override String get templateNameHint => 'e.g. Found Person'; @@ -1421,10 +1440,10 @@ class AppLocalizationsDe extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Importieren'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Exportieren'; @override String deleteTemplateConfirmation(String name) { @@ -1464,17 +1483,17 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Auf Standard zurücksetzen'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'Dadurch werden alle benutzerdefinierten Vorlagen gelöscht und die 4 Standardvorlagen wiederhergestellt. Fortfahren?'; @override - String get reset => 'Reset'; + String get reset => 'Zurücksetzen'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => 'Vorlagen auf Standard zurückgesetzt'; @override String get noTemplates => 'No templates available'; @@ -1561,4 +1580,162 @@ class AppLocalizationsDe extends AppLocalizations { @override String get channel => 'Kanal'; + + @override + String get samplePoliceLead => 'Polizeiführer'; + + @override + String get sampleDroneOperator => 'Drohnenbediener'; + + @override + String get sampleFirefighterAlpha => 'Feuerwehrmann'; + + @override + String get sampleMedicCharlie => 'Sanitäter'; + + @override + String get sampleCommandDelta => 'Kommando'; + + @override + String get sampleFireEngine => 'Feuerwehrfahrzeug'; + + @override + String get sampleAirSupport => 'Luftunterstützung'; + + @override + String get sampleBaseCoordinator => 'Basiskoordinator'; + + @override + String get channelEmergency => 'Notfall'; + + @override + String get channelCoordination => 'Koordination'; + + @override + String get channelUpdates => 'Aktualisierungen'; + + @override + String get sampleTeamMember => 'Beispiel-Teammitglied'; + + @override + String get sampleScout => 'Beispiel-Späher'; + + @override + String get sampleBase => 'Beispiel-Basis'; + + @override + String get sampleSearcher => 'Beispiel-Sucher'; + + @override + String get sampleObjectBackpack => ' Rucksack gefunden - blaue Farbe'; + + @override + String get sampleObjectVehicle => ' Fahrzeug verlassen - Besitzer prüfen'; + + @override + String get sampleObjectCamping => ' Campingausrüstung entdeckt'; + + @override + String get sampleObjectTrailMarker => + ' Wegmarkierung abseits des Pfades gefunden'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Alle Teams melden'; + + @override + String get sampleMsgWeatherUpdate => + 'Wetterupdate: Klarer Himmel, Temp. 18°C'; + + @override + String get sampleMsgBaseCamp => 'Basislager am Sammelplatz eingerichtet'; + + @override + String get sampleMsgTeamAlpha => 'Team bewegt sich zu Sektor 2'; + + @override + String get sampleMsgRadioCheck => 'Funkcheck - alle Stationen antworten'; + + @override + String get sampleMsgWaterSupply => + 'Wasserversorgung verfügbar an Kontrollpunkt 3'; + + @override + String get sampleMsgTeamBravo => 'Team meldet: Sektor 1 frei'; + + @override + String get sampleMsgEtaRallyPoint => + 'Ankunftszeit am Sammelpunkt: 15 Minuten'; + + @override + String get sampleMsgSupplyDrop => 'Versorgungsabwurf bestätigt für 14:00'; + + @override + String get sampleMsgDroneSurvey => + 'Drohnenüberwachung abgeschlossen - keine Funde'; + + @override + String get sampleMsgTeamCharlie => 'Team fordert Unterstützung an'; + + @override + String get sampleMsgRadioDiscipline => + 'An alle Einheiten: Funkdisziplin wahren'; + + @override + String get sampleMsgUrgentMedical => + 'DRINGEND: Medizinische Hilfe benötigt in Sektor 4'; + + @override + String get sampleMsgAdultMale => ' Erwachsener Mann, bei Bewusstsein'; + + @override + String get sampleMsgFireSpotted => 'Feuer gesichtet - Koordinaten folgen'; + + @override + String get sampleMsgSpreadingRapidly => ' Breitet sich schnell aus!'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORITÄT: Brauche Hubschrauberunterstützung'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Medizinisches Team auf dem Weg zu Ihrem Standort'; + + @override + String get sampleMsgEvacHelicopter => + 'Evakuierungshubschrauber ETA 10 Minuten'; + + @override + String get sampleMsgEmergencyResolved => 'Notfall behoben - alles klar'; + + @override + String get sampleMsgEmergencyStagingArea => ' Notfall-Sammelplatz'; + + @override + String get sampleMsgEmergencyServices => + 'Rettungsdienste benachrichtigt und auf dem Weg'; + + @override + String get sampleAlphaTeamLead => 'Team-Leiter'; + + @override + String get sampleBravoScout => 'Späher'; + + @override + String get sampleCharlieMedic => 'Sanitäter'; + + @override + String get sampleDeltaNavigator => 'Navigator'; + + @override + String get sampleEchoSupport => 'Unterstützung'; + + @override + String get sampleBaseCommand => 'Basis-Kommando'; + + @override + String get sampleFieldCoordinator => 'Feldkoordinator'; + + @override + String get sampleMedicalTeam => 'Medizinisches Team'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 8df993c..73edb58 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1031,6 +1031,25 @@ class AppLocalizationsEn extends AppLocalizations { String get deleteMessageConfirmation => 'Are you sure you want to delete this message?'; + @override + String get shareLocation => 'Share location'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nCoordinates: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'SAR Location'; + + @override + String get locationShared => 'Location shared'; + @override String get refreshedContacts => 'Refreshed contacts'; @@ -1545,4 +1564,154 @@ class AppLocalizationsEn extends AppLocalizations { @override String get channel => 'Channel'; + + @override + String get samplePoliceLead => 'Police Lead'; + + @override + String get sampleDroneOperator => 'Drone Operator'; + + @override + String get sampleFirefighterAlpha => 'Firefighter'; + + @override + String get sampleMedicCharlie => 'Medic'; + + @override + String get sampleCommandDelta => 'Command'; + + @override + String get sampleFireEngine => 'Fire Engine'; + + @override + String get sampleAirSupport => 'Air Support'; + + @override + String get sampleBaseCoordinator => 'Base Coordinator'; + + @override + String get channelEmergency => 'Emergency'; + + @override + String get channelCoordination => 'Coordination'; + + @override + String get channelUpdates => 'Updates'; + + @override + String get sampleTeamMember => 'Sample Team Member'; + + @override + String get sampleScout => 'Sample Scout'; + + @override + String get sampleBase => 'Sample Base'; + + @override + String get sampleSearcher => 'Sample Searcher'; + + @override + String get sampleObjectBackpack => ' Backpack found - blue color'; + + @override + String get sampleObjectVehicle => ' Vehicle abandoned - check for owner'; + + @override + String get sampleObjectCamping => ' Camping equipment discovered'; + + @override + String get sampleObjectTrailMarker => ' Trail marker found off-path'; + + @override + String get sampleMsgAllTeamsCheckIn => 'All teams check in'; + + @override + String get sampleMsgWeatherUpdate => 'Weather update: Clear skies, temp 18°C'; + + @override + String get sampleMsgBaseCamp => 'Base camp established at staging area'; + + @override + String get sampleMsgTeamAlpha => 'Team moving to sector 2'; + + @override + String get sampleMsgRadioCheck => 'Radio check - all stations respond'; + + @override + String get sampleMsgWaterSupply => 'Water supply available at checkpoint 3'; + + @override + String get sampleMsgTeamBravo => 'Team reporting: sector 1 clear'; + + @override + String get sampleMsgEtaRallyPoint => 'ETA to rally point: 15 minutes'; + + @override + String get sampleMsgSupplyDrop => 'Supply drop confirmed for 14:00'; + + @override + String get sampleMsgDroneSurvey => 'Drone survey completed - no findings'; + + @override + String get sampleMsgTeamCharlie => 'Team requesting backup'; + + @override + String get sampleMsgRadioDiscipline => 'All units: maintain radio discipline'; + + @override + String get sampleMsgUrgentMedical => + 'URGENT: Medical assistance needed at sector 4'; + + @override + String get sampleMsgAdultMale => ' Adult male, conscious'; + + @override + String get sampleMsgFireSpotted => 'Fire spotted - coordinates incoming'; + + @override + String get sampleMsgSpreadingRapidly => ' Spreading rapidly!'; + + @override + String get sampleMsgPriorityHelicopter => 'PRIORITY: Need helicopter support'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Medical team en route to your location'; + + @override + String get sampleMsgEvacHelicopter => 'Evac helicopter ETA 10 minutes'; + + @override + String get sampleMsgEmergencyResolved => 'Emergency resolved - all clear'; + + @override + String get sampleMsgEmergencyStagingArea => ' Emergency staging area'; + + @override + String get sampleMsgEmergencyServices => + 'Emergency services notified and responding'; + + @override + String get sampleAlphaTeamLead => 'Team Lead'; + + @override + String get sampleBravoScout => 'Scout'; + + @override + String get sampleCharlieMedic => 'Medic'; + + @override + String get sampleDeltaNavigator => 'Navigator'; + + @override + String get sampleEchoSupport => 'Support'; + + @override + String get sampleBaseCommand => 'Base Command'; + + @override + String get sampleFieldCoordinator => 'Field Coordinator'; + + @override + String get sampleMedicalTeam => 'Medical Team'; } diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index fd191e3..d6b25cc 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -1037,6 +1037,25 @@ class AppLocalizationsEs extends AppLocalizations { String get deleteMessageConfirmation => '¿Está seguro de que desea eliminar este mensaje?'; + @override + String get shareLocation => 'Compartir ubicación'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nCoordenadas: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'Ubicación SAR'; + + @override + String get locationShared => 'Ubicación compartida'; + @override String get refreshedContacts => 'Contactos actualizados'; @@ -1374,22 +1393,22 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'Plantillas SAR'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'Gestionar plantillas SAR'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Agregar plantilla'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Editar plantilla'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Eliminar plantilla'; @override - String get templateName => 'Template Name'; + String get templateName => 'Nombre de plantilla'; @override String get templateNameHint => 'e.g. Found Person'; @@ -1416,10 +1435,10 @@ class AppLocalizationsEs extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Importar'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Exportar'; @override String deleteTemplateConfirmation(String name) { @@ -1459,17 +1478,18 @@ class AppLocalizationsEs extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Restablecer valores predeterminados'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'Esto eliminará todas las plantillas personalizadas y restaurará las 4 plantillas predeterminadas. ¿Continuar?'; @override - String get reset => 'Reset'; + String get reset => 'Restablecer'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => + 'Plantillas restablecidas a valores predeterminados'; @override String get noTemplates => 'No templates available'; @@ -1556,4 +1576,167 @@ class AppLocalizationsEs extends AppLocalizations { @override String get channel => 'Canal'; + + @override + String get samplePoliceLead => 'Jefe de Policía'; + + @override + String get sampleDroneOperator => 'Operador de Dron'; + + @override + String get sampleFirefighterAlpha => 'Bombero'; + + @override + String get sampleMedicCharlie => 'Médico'; + + @override + String get sampleCommandDelta => 'Comando'; + + @override + String get sampleFireEngine => 'Camión de Bomberos'; + + @override + String get sampleAirSupport => 'Apoyo Aéreo'; + + @override + String get sampleBaseCoordinator => 'Coordinador de Base'; + + @override + String get channelEmergency => 'Emergencia'; + + @override + String get channelCoordination => 'Coordinación'; + + @override + String get channelUpdates => 'Actualizaciones'; + + @override + String get sampleTeamMember => 'Miembro de Equipo de Muestra'; + + @override + String get sampleScout => 'Explorador de Muestra'; + + @override + String get sampleBase => 'Base de Muestra'; + + @override + String get sampleSearcher => 'Buscador de Muestra'; + + @override + String get sampleObjectBackpack => ' Mochila encontrada - color azul'; + + @override + String get sampleObjectVehicle => + ' Vehículo abandonado - verificar propietario'; + + @override + String get sampleObjectCamping => ' Equipo de camping descubierto'; + + @override + String get sampleObjectTrailMarker => + ' Marcador de sendero encontrado fuera del camino'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Todos los equipos reporten'; + + @override + String get sampleMsgWeatherUpdate => + 'Actualización del clima: Cielo despejado, temp 18°C'; + + @override + String get sampleMsgBaseCamp => + 'Campamento base establecido en área de preparación'; + + @override + String get sampleMsgTeamAlpha => 'Equipo moviéndose al sector 2'; + + @override + String get sampleMsgRadioCheck => + 'Prueba de radio - todas las estaciones respondan'; + + @override + String get sampleMsgWaterSupply => + 'Suministro de agua disponible en punto de control 3'; + + @override + String get sampleMsgTeamBravo => 'Equipo reportando: sector 1 despejado'; + + @override + String get sampleMsgEtaRallyPoint => 'ETA al punto de encuentro: 15 minutos'; + + @override + String get sampleMsgSupplyDrop => + 'Caída de suministros confirmada para las 14:00'; + + @override + String get sampleMsgDroneSurvey => + 'Inspección con dron completada - sin hallazgos'; + + @override + String get sampleMsgTeamCharlie => 'Equipo solicitando apoyo'; + + @override + String get sampleMsgRadioDiscipline => + 'Todas las unidades: mantener disciplina de radio'; + + @override + String get sampleMsgUrgentMedical => + 'URGENTE: Asistencia médica necesaria en sector 4'; + + @override + String get sampleMsgAdultMale => ' Hombre adulto, consciente'; + + @override + String get sampleMsgFireSpotted => 'Fuego avistado - coordenadas próximas'; + + @override + String get sampleMsgSpreadingRapidly => ' ¡Se propaga rápidamente!'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORIDAD: Necesitamos apoyo de helicóptero'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Equipo médico en camino a su ubicación'; + + @override + String get sampleMsgEvacHelicopter => + 'Helicóptero de evacuación ETA 10 minutos'; + + @override + String get sampleMsgEmergencyResolved => + 'Emergencia resuelta - todo despejado'; + + @override + String get sampleMsgEmergencyStagingArea => + ' Área de preparación de emergencia'; + + @override + String get sampleMsgEmergencyServices => + 'Servicios de emergencia notificados y respondiendo'; + + @override + String get sampleAlphaTeamLead => 'Líder de Equipo'; + + @override + String get sampleBravoScout => 'Explorador'; + + @override + String get sampleCharlieMedic => 'Médico'; + + @override + String get sampleDeltaNavigator => 'Navegador'; + + @override + String get sampleEchoSupport => 'Apoyo'; + + @override + String get sampleBaseCommand => 'Comando de Base'; + + @override + String get sampleFieldCoordinator => 'Coordinador de Campo'; + + @override + String get sampleMedicalTeam => 'Equipo Médico'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 6316c16..7155b97 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -1042,6 +1042,25 @@ class AppLocalizationsFr extends AppLocalizations { String get deleteMessageConfirmation => 'Êtes-vous sûr de vouloir supprimer ce message?'; + @override + String get shareLocation => 'Partager la position'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nCoordonnées: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'Position SAR'; + + @override + String get locationShared => 'Position partagée'; + @override String get refreshedContacts => 'Contacts actualisés'; @@ -1382,22 +1401,22 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'Modèles SAR'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'Gérer les modèles SAR'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Ajouter un modèle'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Modifier le modèle'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Supprimer le modèle'; @override - String get templateName => 'Template Name'; + String get templateName => 'Nom du modèle'; @override String get templateNameHint => 'e.g. Found Person'; @@ -1424,10 +1443,10 @@ class AppLocalizationsFr extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Importer'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Exporter'; @override String deleteTemplateConfirmation(String name) { @@ -1467,17 +1486,17 @@ class AppLocalizationsFr extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Réinitialiser aux valeurs par défaut'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'Cela supprimera tous les modèles personnalisés et restaurera les 4 modèles par défaut. Continuer?'; @override - String get reset => 'Reset'; + String get reset => 'Réinitialiser'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => 'Modèles réinitialisés aux valeurs par défaut'; @override String get noTemplates => 'No templates available'; @@ -1564,4 +1583,166 @@ class AppLocalizationsFr extends AppLocalizations { @override String get channel => 'Canal'; + + @override + String get samplePoliceLead => 'Chef de Police'; + + @override + String get sampleDroneOperator => 'Opérateur de Drone'; + + @override + String get sampleFirefighterAlpha => 'Pompier'; + + @override + String get sampleMedicCharlie => 'Médecin'; + + @override + String get sampleCommandDelta => 'Commandement'; + + @override + String get sampleFireEngine => 'Camion de Pompiers'; + + @override + String get sampleAirSupport => 'Soutien Aérien'; + + @override + String get sampleBaseCoordinator => 'Coordinateur de Base'; + + @override + String get channelEmergency => 'Urgence'; + + @override + String get channelCoordination => 'Coordination'; + + @override + String get channelUpdates => 'Mises à jour'; + + @override + String get sampleTeamMember => 'Membre d\'Équipe Exemple'; + + @override + String get sampleScout => 'Éclaireur Exemple'; + + @override + String get sampleBase => 'Base Exemple'; + + @override + String get sampleSearcher => 'Chercheur Exemple'; + + @override + String get sampleObjectBackpack => ' Sac à dos trouvé - couleur bleue'; + + @override + String get sampleObjectVehicle => + ' Véhicule abandonné - vérifier le propriétaire'; + + @override + String get sampleObjectCamping => ' Équipement de camping découvert'; + + @override + String get sampleObjectTrailMarker => ' Balise de sentier trouvée hors piste'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Toutes les équipes se signaler'; + + @override + String get sampleMsgWeatherUpdate => + 'Mise à jour météo : Ciel dégagé, temp 18°C'; + + @override + String get sampleMsgBaseCamp => + 'Camp de base établi à la zone de rassemblement'; + + @override + String get sampleMsgTeamAlpha => 'Équipe se déplaçant vers le secteur 2'; + + @override + String get sampleMsgRadioCheck => + 'Test radio - toutes les stations répondent'; + + @override + String get sampleMsgWaterSupply => + 'Approvisionnement en eau disponible au point de contrôle 3'; + + @override + String get sampleMsgTeamBravo => 'Équipe signale : secteur 1 dégagé'; + + @override + String get sampleMsgEtaRallyPoint => + 'ETA au point de ralliement : 15 minutes'; + + @override + String get sampleMsgSupplyDrop => + 'Largage de ravitaillement confirmé pour 14h00'; + + @override + String get sampleMsgDroneSurvey => + 'Surveillance par drone terminée - aucune découverte'; + + @override + String get sampleMsgTeamCharlie => 'Équipe demande du renfort'; + + @override + String get sampleMsgRadioDiscipline => + 'Toutes les unités : maintenir la discipline radio'; + + @override + String get sampleMsgUrgentMedical => + 'URGENT : Assistance médicale nécessaire au secteur 4'; + + @override + String get sampleMsgAdultMale => ' Homme adulte, conscient'; + + @override + String get sampleMsgFireSpotted => 'Feu repéré - coordonnées à venir'; + + @override + String get sampleMsgSpreadingRapidly => ' Se propage rapidement !'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORITÉ : Besoin de soutien hélicoptère'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Équipe médicale en route vers votre position'; + + @override + String get sampleMsgEvacHelicopter => + 'Hélicoptère d\'évacuation ETA 10 minutes'; + + @override + String get sampleMsgEmergencyResolved => 'Urgence résolue - tout est clair'; + + @override + String get sampleMsgEmergencyStagingArea => + ' Zone de rassemblement d\'urgence'; + + @override + String get sampleMsgEmergencyServices => + 'Services d\'urgence notifiés et en réponse'; + + @override + String get sampleAlphaTeamLead => 'Chef d\'Équipe'; + + @override + String get sampleBravoScout => 'Éclaireur'; + + @override + String get sampleCharlieMedic => 'Médecin'; + + @override + String get sampleDeltaNavigator => 'Navigateur'; + + @override + String get sampleEchoSupport => 'Soutien'; + + @override + String get sampleBaseCommand => 'Commandement de Base'; + + @override + String get sampleFieldCoordinator => 'Coordinateur de Terrain'; + + @override + String get sampleMedicalTeam => 'Équipe Médicale'; } diff --git a/lib/l10n/app_localizations_hr.dart b/lib/l10n/app_localizations_hr.dart index 7315f79..e335d80 100644 --- a/lib/l10n/app_localizations_hr.dart +++ b/lib/l10n/app_localizations_hr.dart @@ -1033,6 +1033,25 @@ class AppLocalizationsHr extends AppLocalizations { String get deleteMessageConfirmation => 'Jeste li sigurni da želite izbrisati ovu poruku?'; + @override + String get shareLocation => 'Podijeli lokaciju'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nKoordinate: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'SAR Lokacija'; + + @override + String get locationShared => 'Lokacija podijeljena'; + @override String get refreshedContacts => 'Kontakti osvježeni'; @@ -1367,25 +1386,25 @@ class AppLocalizationsHr extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'SAR predlošci'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'Upravljanje SAR predlošcima'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Dodaj predložak'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Uredi predložak'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Izbriši predložak'; @override - String get templateName => 'Template Name'; + String get templateName => 'Naziv predloška'; @override - String get templateNameHint => 'e.g. Found Person'; + String get templateNameHint => 'npr. Pronađena osoba'; @override String get templateEmoji => 'Emoji'; @@ -1409,10 +1428,10 @@ class AppLocalizationsHr extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Uvezi'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Izvezi'; @override String deleteTemplateConfirmation(String name) { @@ -1452,17 +1471,17 @@ class AppLocalizationsHr extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Vrati na zadane'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'Ovo će izbrisati sve prilagođene predloške i vratiti 4 zadana predloška. Nastaviti?'; @override - String get reset => 'Reset'; + String get reset => 'Vrati'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => 'Predlošci vraćeni na zadane'; @override String get noTemplates => 'No templates available'; @@ -1548,4 +1567,159 @@ class AppLocalizationsHr extends AppLocalizations { @override String get channel => 'Kanal'; + + @override + String get samplePoliceLead => 'Voditelj Policije'; + + @override + String get sampleDroneOperator => 'Operater Drona'; + + @override + String get sampleFirefighterAlpha => 'Vatrogasac'; + + @override + String get sampleMedicCharlie => 'Medičar'; + + @override + String get sampleCommandDelta => 'Zapovjedništvo'; + + @override + String get sampleFireEngine => 'Vatrogasno Vozilo'; + + @override + String get sampleAirSupport => 'Zračna Podrška'; + + @override + String get sampleBaseCoordinator => 'Koordinator Baze'; + + @override + String get channelEmergency => 'Hitno'; + + @override + String get channelCoordination => 'Koordinacija'; + + @override + String get channelUpdates => 'Ažuriranja'; + + @override + String get sampleTeamMember => 'Primjer Člana Tima'; + + @override + String get sampleScout => 'Primjer Izviđača'; + + @override + String get sampleBase => 'Primjer Baze'; + + @override + String get sampleSearcher => 'Primjer Tragača'; + + @override + String get sampleObjectBackpack => ' Pronađen ruksak - plava boja'; + + @override + String get sampleObjectVehicle => ' Napušteno vozilo - provjeriti vlasnika'; + + @override + String get sampleObjectCamping => ' Otkrivena oprema za kampiranje'; + + @override + String get sampleObjectTrailMarker => ' Oznaka staze pronađena izvan puta'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Svi timovi se jave'; + + @override + String get sampleMsgWeatherUpdate => + 'Ažuriranje vremena: Vedro nebo, temp 18°C'; + + @override + String get sampleMsgBaseCamp => 'Bazni kamp uspostavljen na okupljalište'; + + @override + String get sampleMsgTeamAlpha => 'Tim se kreće prema sektoru 2'; + + @override + String get sampleMsgRadioCheck => 'Provjera radija - sve stanice odgovorite'; + + @override + String get sampleMsgWaterSupply => + 'Opskrba vodom dostupna na kontrolnoj točki 3'; + + @override + String get sampleMsgTeamBravo => 'Tim izvještava: sektor 1 čist'; + + @override + String get sampleMsgEtaRallyPoint => 'ETA do točke okupljanja: 15 minuta'; + + @override + String get sampleMsgSupplyDrop => 'Isporuka zaliha potvrđena za 14:00'; + + @override + String get sampleMsgDroneSurvey => 'Nadzor dronom završen - bez nalaza'; + + @override + String get sampleMsgTeamCharlie => 'Tim traži pojačanje'; + + @override + String get sampleMsgRadioDiscipline => + 'Sve jedinice: održavati radio disciplinu'; + + @override + String get sampleMsgUrgentMedical => + 'HITNO: Potrebna medicinska pomoć u sektoru 4'; + + @override + String get sampleMsgAdultMale => ' Odrasli muškarac, pri svijesti'; + + @override + String get sampleMsgFireSpotted => 'Uočen požar - koordinate slijede'; + + @override + String get sampleMsgSpreadingRapidly => ' Širi se brzo!'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORITET: Potrebna podrška helikoptera'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Medicinski tim na putu do vaše lokacije'; + + @override + String get sampleMsgEvacHelicopter => + 'Helikopter za evakuaciju ETA 10 minuta'; + + @override + String get sampleMsgEmergencyResolved => 'Hitnost riješena - sve čisto'; + + @override + String get sampleMsgEmergencyStagingArea => ' Hitno okupljalište'; + + @override + String get sampleMsgEmergencyServices => + 'Hitne službe obaviještene i odgovaraju'; + + @override + String get sampleAlphaTeamLead => 'Voditelj Tima'; + + @override + String get sampleBravoScout => 'Izviđač'; + + @override + String get sampleCharlieMedic => 'Medičar'; + + @override + String get sampleDeltaNavigator => 'Navigator'; + + @override + String get sampleEchoSupport => 'Podrška'; + + @override + String get sampleBaseCommand => 'Zapovjedništvo Baze'; + + @override + String get sampleFieldCoordinator => 'Terenski Koordinator'; + + @override + String get sampleMedicalTeam => 'Medicinski Tim'; } diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 3e48b22..34d29e0 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -1039,6 +1039,25 @@ class AppLocalizationsIt extends AppLocalizations { String get deleteMessageConfirmation => 'Sei sicuro di voler eliminare questo messaggio?'; + @override + String get shareLocation => 'Condividi posizione'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nCoordinate: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'Posizione SAR'; + + @override + String get locationShared => 'Posizione condivisa'; + @override String get refreshedContacts => 'Contatti aggiornati'; @@ -1377,22 +1396,22 @@ class AppLocalizationsIt extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'Modelli SAR'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'Gestisci modelli SAR'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Aggiungi modello'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Modifica modello'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Elimina modello'; @override - String get templateName => 'Template Name'; + String get templateName => 'Nome modello'; @override String get templateNameHint => 'e.g. Found Person'; @@ -1419,10 +1438,10 @@ class AppLocalizationsIt extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Importa'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Esporta'; @override String deleteTemplateConfirmation(String name) { @@ -1462,17 +1481,17 @@ class AppLocalizationsIt extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Ripristina predefiniti'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'Questo eliminerà tutti i modelli personalizzati e ripristinerà i 4 modelli predefiniti. Continuare?'; @override - String get reset => 'Reset'; + String get reset => 'Ripristina'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => 'Modelli ripristinati ai valori predefiniti'; @override String get noTemplates => 'No templates available'; @@ -1558,4 +1577,164 @@ class AppLocalizationsIt extends AppLocalizations { @override String get channel => 'Canale'; + + @override + String get samplePoliceLead => 'Capo della Polizia'; + + @override + String get sampleDroneOperator => 'Operatore Drone'; + + @override + String get sampleFirefighterAlpha => 'Vigile del Fuoco'; + + @override + String get sampleMedicCharlie => 'Medico'; + + @override + String get sampleCommandDelta => 'Comando'; + + @override + String get sampleFireEngine => 'Autopompa'; + + @override + String get sampleAirSupport => 'Supporto Aereo'; + + @override + String get sampleBaseCoordinator => 'Coordinatore di Base'; + + @override + String get channelEmergency => 'Emergenza'; + + @override + String get channelCoordination => 'Coordinamento'; + + @override + String get channelUpdates => 'Aggiornamenti'; + + @override + String get sampleTeamMember => 'Membro del Team di Esempio'; + + @override + String get sampleScout => 'Esploratore di Esempio'; + + @override + String get sampleBase => 'Base di Esempio'; + + @override + String get sampleSearcher => 'Cercatore di Esempio'; + + @override + String get sampleObjectBackpack => ' Zaino trovato - colore blu'; + + @override + String get sampleObjectVehicle => + ' Veicolo abbandonato - controllare il proprietario'; + + @override + String get sampleObjectCamping => ' Attrezzatura da campeggio scoperta'; + + @override + String get sampleObjectTrailMarker => ' Segnavia trovato fuori sentiero'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Tutti i team segnalarsi'; + + @override + String get sampleMsgWeatherUpdate => + 'Aggiornamento meteo: Cielo sereno, temp 18°C'; + + @override + String get sampleMsgBaseCamp => 'Campo base stabilito all\'area di raduno'; + + @override + String get sampleMsgTeamAlpha => 'Team si sta spostando al settore 2'; + + @override + String get sampleMsgRadioCheck => + 'Controllo radio - tutte le stazioni rispondano'; + + @override + String get sampleMsgWaterSupply => + 'Rifornimento idrico disponibile al punto di controllo 3'; + + @override + String get sampleMsgTeamBravo => 'Team segnala: settore 1 libero'; + + @override + String get sampleMsgEtaRallyPoint => 'ETA al punto di raduno: 15 minuti'; + + @override + String get sampleMsgSupplyDrop => + 'Lancio rifornimenti confermato per le 14:00'; + + @override + String get sampleMsgDroneSurvey => + 'Sorveglianza con drone completata - nessun ritrovamento'; + + @override + String get sampleMsgTeamCharlie => 'Team richiede rinforzi'; + + @override + String get sampleMsgRadioDiscipline => + 'Tutte le unità: mantenere disciplina radio'; + + @override + String get sampleMsgUrgentMedical => + 'URGENTE: Assistenza medica necessaria al settore 4'; + + @override + String get sampleMsgAdultMale => ' Uomo adulto, cosciente'; + + @override + String get sampleMsgFireSpotted => + 'Incendio avvistato - coordinate in arrivo'; + + @override + String get sampleMsgSpreadingRapidly => ' Si sta diffondendo rapidamente!'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORITÀ: Necessario supporto elicottero'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Team medico in rotta verso la vostra posizione'; + + @override + String get sampleMsgEvacHelicopter => + 'Elicottero di evacuazione ETA 10 minuti'; + + @override + String get sampleMsgEmergencyResolved => 'Emergenza risolta - tutto libero'; + + @override + String get sampleMsgEmergencyStagingArea => ' Area di raduno di emergenza'; + + @override + String get sampleMsgEmergencyServices => + 'Servizi di emergenza notificati e in risposta'; + + @override + String get sampleAlphaTeamLead => 'Capo Team'; + + @override + String get sampleBravoScout => 'Esploratore'; + + @override + String get sampleCharlieMedic => 'Medico'; + + @override + String get sampleDeltaNavigator => 'Navigatore'; + + @override + String get sampleEchoSupport => 'Supporto'; + + @override + String get sampleBaseCommand => 'Comando di Base'; + + @override + String get sampleFieldCoordinator => 'Coordinatore sul Campo'; + + @override + String get sampleMedicalTeam => 'Team Medico'; } diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 6c64fdb..5f076d0 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -1033,6 +1033,25 @@ class AppLocalizationsSl extends AppLocalizations { String get deleteMessageConfirmation => 'Ali ste prepričani, da želite izbrisati to sporočilo?'; + @override + String get shareLocation => 'Deli lokacijo'; + + @override + String shareLocationText( + String markerInfo, + String lat, + String lon, + String url, + ) { + return '$markerInfo\n\nKoordinate: $lat, $lon\n\nGoogle Maps: $url'; + } + + @override + String get sarLocationShare => 'SAR Lokacija'; + + @override + String get locationShared => 'Lokacija deljena'; + @override String get refreshedContacts => 'Stiki osveženi'; @@ -1370,25 +1389,25 @@ class AppLocalizationsSl extends AppLocalizations { } @override - String get sarTemplates => 'SAR Templates'; + String get sarTemplates => 'SAR predloge'; @override - String get manageSarTemplates => 'Manage cursor on target templates'; + String get manageSarTemplates => 'Upravljanje SAR predlog'; @override - String get addTemplate => 'Add Template'; + String get addTemplate => 'Dodaj predlogo'; @override - String get editTemplate => 'Edit Template'; + String get editTemplate => 'Uredi predlogo'; @override - String get deleteTemplate => 'Delete Template'; + String get deleteTemplate => 'Izbriši predlogo'; @override - String get templateName => 'Template Name'; + String get templateName => 'Ime predloge'; @override - String get templateNameHint => 'e.g. Found Person'; + String get templateNameHint => 'npr. Najdena oseba'; @override String get templateEmoji => 'Emoji'; @@ -1412,10 +1431,10 @@ class AppLocalizationsSl extends AppLocalizations { String get previewFormat => 'Preview (SAR Message Format)'; @override - String get importFromClipboard => 'Import'; + String get importFromClipboard => 'Uvozi'; @override - String get exportToClipboard => 'Export'; + String get exportToClipboard => 'Izvozi'; @override String deleteTemplateConfirmation(String name) { @@ -1455,17 +1474,17 @@ class AppLocalizationsSl extends AppLocalizations { } @override - String get resetToDefaults => 'Reset to Defaults'; + String get resetToDefaults => 'Ponastavi na privzeto'; @override String get resetToDefaultsConfirmation => - 'This will delete all custom templates and restore the 4 default templates. Continue?'; + 'To bo izbrisalo vse prilagojene predloge in obnovilo 4 privzete predloge. Nadaljevati?'; @override - String get reset => 'Reset'; + String get reset => 'Ponastavi'; @override - String get resetComplete => 'Templates reset to defaults'; + String get resetComplete => 'Predloge ponastavljene na privzeto'; @override String get noTemplates => 'No templates available'; @@ -1550,4 +1569,160 @@ class AppLocalizationsSl extends AppLocalizations { @override String get channel => 'Kanal'; + + @override + String get samplePoliceLead => 'Vodja Policije'; + + @override + String get sampleDroneOperator => 'Operater Drona'; + + @override + String get sampleFirefighterAlpha => 'Gasilec'; + + @override + String get sampleMedicCharlie => 'Zdravnik'; + + @override + String get sampleCommandDelta => 'Poveljstvo'; + + @override + String get sampleFireEngine => 'Gasilsko Vozilo'; + + @override + String get sampleAirSupport => 'Zračna Podpora'; + + @override + String get sampleBaseCoordinator => 'Koordinator Baze'; + + @override + String get channelEmergency => 'Nujno'; + + @override + String get channelCoordination => 'Koordinacija'; + + @override + String get channelUpdates => 'Posodobitve'; + + @override + String get sampleTeamMember => 'Vzorčni Član Ekipe'; + + @override + String get sampleScout => 'Vzorčni Izvidnik'; + + @override + String get sampleBase => 'Vzorčna Baza'; + + @override + String get sampleSearcher => 'Vzorčni Iskalec'; + + @override + String get sampleObjectBackpack => ' Najden nahrbtnik - modra barva'; + + @override + String get sampleObjectVehicle => ' Zapuščeno vozilo - preveriti lastnika'; + + @override + String get sampleObjectCamping => ' Odkrita oprema za kampiranje'; + + @override + String get sampleObjectTrailMarker => ' Oznaka poti najdena izven poti'; + + @override + String get sampleMsgAllTeamsCheckIn => 'Vse ekipe se javite'; + + @override + String get sampleMsgWeatherUpdate => + 'Posodobitev vremena: Jasno nebo, temp 18°C'; + + @override + String get sampleMsgBaseCamp => 'Bazni tabor vzpostavljen na zbirališču'; + + @override + String get sampleMsgTeamAlpha => 'Ekipa se premika v sektor 2'; + + @override + String get sampleMsgRadioCheck => + 'Preverjanje radia - vse postaje odgovorite'; + + @override + String get sampleMsgWaterSupply => + 'Oskrba z vodo na voljo na kontrolni točki 3'; + + @override + String get sampleMsgTeamBravo => 'Ekipa poroča: sektor 1 čist'; + + @override + String get sampleMsgEtaRallyPoint => 'Prihod na zbirališče: 15 minut'; + + @override + String get sampleMsgSupplyDrop => 'Dostava zalog potrjena za 14:00'; + + @override + String get sampleMsgDroneSurvey => 'Nadzor z dronom zaključen - brez najdb'; + + @override + String get sampleMsgTeamCharlie => 'Ekipa prosi za okrepitev'; + + @override + String get sampleMsgRadioDiscipline => + 'Vse enote: vzdrževati radijsko disciplino'; + + @override + String get sampleMsgUrgentMedical => + 'NUJNO: Potrebna medicinska pomoč v sektorju 4'; + + @override + String get sampleMsgAdultMale => ' Odrasel moški, pri zavesti'; + + @override + String get sampleMsgFireSpotted => 'Opažen požar - koordinate sledijo'; + + @override + String get sampleMsgSpreadingRapidly => ' Hitro se širi!'; + + @override + String get sampleMsgPriorityHelicopter => + 'PRIORITETA: Potrebna podpora helikopterja'; + + @override + String get sampleMsgMedicalTeamEnRoute => + 'Medicinska ekipa na poti do vaše lokacije'; + + @override + String get sampleMsgEvacHelicopter => + 'Helikopter za evakuacijo prihod 10 minut'; + + @override + String get sampleMsgEmergencyResolved => 'Nujnost rešena - vse čisto'; + + @override + String get sampleMsgEmergencyStagingArea => ' Nujno zbirališče'; + + @override + String get sampleMsgEmergencyServices => + 'Nujne službe obveščene in se odzivajo'; + + @override + String get sampleAlphaTeamLead => 'Vodja Ekipe'; + + @override + String get sampleBravoScout => 'Izvidnik'; + + @override + String get sampleCharlieMedic => 'Zdravnik'; + + @override + String get sampleDeltaNavigator => 'Navigator'; + + @override + String get sampleEchoSupport => 'Podpora'; + + @override + String get sampleBaseCommand => 'Poveljstvo Baze'; + + @override + String get sampleFieldCoordinator => 'Terenski Koordinator'; + + @override + String get sampleMedicalTeam => 'Medicinska Ekipa'; } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 709d751..03cb03c 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -620,6 +620,10 @@ "textCopiedToClipboard": "Besedilo kopirano v odložišče", "deleteMessage": "Izbriši sporočilo", "deleteMessageConfirmation": "Ali ste prepričani, da želite izbrisati to sporočilo?", + "shareLocation": "Deli lokacijo", + "shareLocationText": "{markerInfo}\n\nKoordinate: {lat}, {lon}\n\nGoogle Maps: {url}", + "sarLocationShare": "SAR Lokacija", + "locationShared": "Lokacija deljena", "refreshedContacts": "Stiki osveženi", @@ -790,13 +794,13 @@ "failedToGetLocation": "Pridobivanje lokacije ni uspelo: {error}", - "sarTemplates": "SAR Templates", - "manageSarTemplates": "Manage cursor on target templates", - "addTemplate": "Add Template", - "editTemplate": "Edit Template", - "deleteTemplate": "Delete Template", - "templateName": "Template Name", - "templateNameHint": "e.g. Found Person", + "sarTemplates": "SAR predloge", + "manageSarTemplates": "Upravljanje SAR predlog", + "addTemplate": "Dodaj predlogo", + "editTemplate": "Uredi predlogo", + "deleteTemplate": "Izbriši predlogo", + "templateName": "Ime predloge", + "templateNameHint": "npr. Najdena oseba", "templateEmoji": "Emoji", "emojiRequired": "Emoji je obvezen", "nameRequired": "Ime je obvezno", @@ -804,8 +808,8 @@ "templateDescriptionHint": "Add additional context...", "templateColor": "Color", "previewFormat": "Preview (SAR Message Format)", - "importFromClipboard": "Import", - "exportToClipboard": "Export", + "importFromClipboard": "Uvozi", + "exportToClipboard": "Izvozi", "deleteTemplateConfirmation": "Delete template '{name}'?", "templateAdded": "Template added", "templateUpdated": "Template updated", @@ -814,10 +818,10 @@ "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "importFailed": "Import failed: {error}", "exportFailed": "Export failed: {error}", - "resetToDefaults": "Reset to Defaults", - "resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", - "reset": "Reset", - "resetComplete": "Templates reset to defaults", + "resetToDefaults": "Ponastavi na privzeto", + "resetToDefaultsConfirmation": "To bo izbrisalo vse prilagojene predloge in obnovilo 4 privzete predloge. Nadaljevati?", + "reset": "Ponastavi", + "resetComplete": "Predloge ponastavljene na privzeto", "noTemplates": "No templates available", "tapAddToCreate": "Tap + to create your first template", "ok": "OK", @@ -846,5 +850,55 @@ "noContactsOrRoomsAvailable": "Ni na voljo kontaktov ali sob", "messagesWillBeSentToPublicChannel": "Sporočila bodo poslana na javni kanal", "newMessage": "Novo sporočilo", - "channel": "Kanal" + "channel": "Kanal", + + "samplePoliceLead": "Vodja Policije", + "sampleDroneOperator": "Operater Drona", + "sampleFirefighterAlpha": "Gasilec", + "sampleMedicCharlie": "Zdravnik", + "sampleCommandDelta": "Poveljstvo", + "sampleFireEngine": "Gasilsko Vozilo", + "sampleAirSupport": "Zračna Podpora", + "sampleBaseCoordinator": "Koordinator Baze", + "channelEmergency": "Nujno", + "channelCoordination": "Koordinacija", + "channelUpdates": "Posodobitve", + "sampleTeamMember": "Vzorčni Član Ekipe", + "sampleScout": "Vzorčni Izvidnik", + "sampleBase": "Vzorčna Baza", + "sampleSearcher": "Vzorčni Iskalec", + "sampleObjectBackpack": " Najden nahrbtnik - modra barva", + "sampleObjectVehicle": " Zapuščeno vozilo - preveriti lastnika", + "sampleObjectCamping": " Odkrita oprema za kampiranje", + "sampleObjectTrailMarker": " Oznaka poti najdena izven poti", + "sampleMsgAllTeamsCheckIn": "Vse ekipe se javite", + "sampleMsgWeatherUpdate": "Posodobitev vremena: Jasno nebo, temp 18°C", + "sampleMsgBaseCamp": "Bazni tabor vzpostavljen na zbirališču", + "sampleMsgTeamAlpha": "Ekipa se premika v sektor 2", + "sampleMsgRadioCheck": "Preverjanje radia - vse postaje odgovorite", + "sampleMsgWaterSupply": "Oskrba z vodo na voljo na kontrolni točki 3", + "sampleMsgTeamBravo": "Ekipa poroča: sektor 1 čist", + "sampleMsgEtaRallyPoint": "Prihod na zbirališče: 15 minut", + "sampleMsgSupplyDrop": "Dostava zalog potrjena za 14:00", + "sampleMsgDroneSurvey": "Nadzor z dronom zaključen - brez najdb", + "sampleMsgTeamCharlie": "Ekipa prosi za okrepitev", + "sampleMsgRadioDiscipline": "Vse enote: vzdrževati radijsko disciplino", + "sampleMsgUrgentMedical": "NUJNO: Potrebna medicinska pomoč v sektorju 4", + "sampleMsgAdultMale": " Odrasel moški, pri zavesti", + "sampleMsgFireSpotted": "Opažen požar - koordinate sledijo", + "sampleMsgSpreadingRapidly": " Hitro se širi!", + "sampleMsgPriorityHelicopter": "PRIORITETA: Potrebna podpora helikopterja", + "sampleMsgMedicalTeamEnRoute": "Medicinska ekipa na poti do vaše lokacije", + "sampleMsgEvacHelicopter": "Helikopter za evakuacijo prihod 10 minut", + "sampleMsgEmergencyResolved": "Nujnost rešena - vse čisto", + "sampleMsgEmergencyStagingArea": " Nujno zbirališče", + "sampleMsgEmergencyServices": "Nujne službe obveščene in se odzivajo", + "sampleAlphaTeamLead": "Vodja Ekipe", + "sampleBravoScout": "Izvidnik", + "sampleCharlieMedic": "Zdravnik", + "sampleDeltaNavigator": "Navigator", + "sampleEchoSupport": "Podpora", + "sampleBaseCommand": "Poveljstvo Baze", + "sampleFieldCoordinator": "Terenski Koordinator", + "sampleMedicalTeam": "Medicinska Ekipa" } diff --git a/lib/models/message.dart b/lib/models/message.dart index 1c4e209..906a562 100644 --- a/lib/models/message.dart +++ b/lib/models/message.dart @@ -53,6 +53,7 @@ class Message { final LatLng? sarGpsCoordinates; final String? sarNotes; // Optional message/notes for SAR marker final String? sarCustomEmoji; // Custom emoji for unknown SAR marker types + final int? sarColorIndex; // Color index (0-7) from standard palette // Display metadata final DateTime receivedAt; @@ -94,6 +95,7 @@ class Message { this.sarGpsCoordinates, this.sarNotes, this.sarCustomEmoji, + this.sarColorIndex, required this.receivedAt, this.senderName, this.deliveryStatus = MessageDeliveryStatus.received, @@ -192,6 +194,7 @@ class Message { senderName: senderName, notes: sarNotes, // Use dedicated notes field instead of full text customEmoji: sarCustomEmoji, // Preserve custom emoji for unknown types + colorIndex: sarColorIndex, // Pass through color index ); } @@ -289,6 +292,7 @@ class Message { LatLng? sarGpsCoordinates, String? sarNotes, String? sarCustomEmoji, + int? sarColorIndex, DateTime? receivedAt, String? senderName, MessageDeliveryStatus? deliveryStatus, @@ -319,6 +323,7 @@ class Message { sarGpsCoordinates: sarGpsCoordinates ?? this.sarGpsCoordinates, sarNotes: sarNotes ?? this.sarNotes, sarCustomEmoji: sarCustomEmoji ?? this.sarCustomEmoji, + sarColorIndex: sarColorIndex ?? this.sarColorIndex, receivedAt: receivedAt ?? this.receivedAt, senderName: senderName ?? this.senderName, deliveryStatus: deliveryStatus ?? this.deliveryStatus, diff --git a/lib/models/sar_marker.dart b/lib/models/sar_marker.dart index 3a9dc97..a8f658f 100644 --- a/lib/models/sar_marker.dart +++ b/lib/models/sar_marker.dart @@ -77,6 +77,7 @@ class SarMarker { final String? senderName; final String? notes; final String? customEmoji; // For custom SAR markers not in predefined types + final int? colorIndex; // Color index (0-7) from standard palette SarMarker({ required this.id, @@ -87,6 +88,7 @@ class SarMarker { this.senderName, this.notes, this.customEmoji, + this.colorIndex, }); /// Get sender public key as hex string (short) @@ -164,6 +166,7 @@ class SarMarker { String? senderName, String? notes, String? customEmoji, + int? colorIndex, }) { return SarMarker( id: id ?? this.id, @@ -174,6 +177,7 @@ class SarMarker { senderName: senderName ?? this.senderName, notes: notes ?? this.notes, customEmoji: customEmoji ?? this.customEmoji, + colorIndex: colorIndex ?? this.colorIndex, ); } diff --git a/lib/models/sar_template.dart b/lib/models/sar_template.dart index c9ebb9f..79ff7d7 100644 --- a/lib/models/sar_template.dart +++ b/lib/models/sar_template.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import '../l10n/app_localizations.dart'; /// SAR Template - Customizable template for SAR (Cursor on Target) messages class SarTemplate { @@ -9,6 +10,19 @@ class SarTemplate { final String colorHex; final bool isDefault; + /// Standard color palette for SAR markers (index 0-7) + /// This palette is used for transmission to ensure consistent colors across devices + static const List colorPalette = [ + '#F44336', // 0 - Red + '#2196F3', // 1 - Blue + '#4CAF50', // 2 - Green + '#FFC107', // 3 - Yellow + '#FF9800', // 4 - Orange + '#9C27B0', // 5 - Purple + '#E91E63', // 6 - Pink + '#00BCD4', // 7 - Cyan + ]; + SarTemplate({ required this.id, required this.emoji, @@ -24,6 +38,77 @@ class SarTemplate { return Color(int.parse('FF$hexCode', radix: 16)); } + /// Get localized display name for this template + /// Returns localized name for default templates, or the stored name for custom templates + String getLocalizedName(BuildContext context) { + final l10n = AppLocalizations.of(context); + if (l10n == null) return name; + + // Return localized names for default templates + switch (id) { + case 'default_found_person': + return l10n.sarMarkerFoundPerson; + case 'default_fire': + return l10n.sarMarkerFire; + case 'default_staging_area': + return l10n.sarMarkerStagingArea; + case 'default_object': + return l10n.sarMarkerObject; + default: + // For custom templates, return the stored name + return name; + } + } + + /// Get the closest color index from the standard palette + /// Returns 0-7 for standard colors, or the closest match + int getColorIndex() { + // Normalize both colors to uppercase for comparison + final normalizedColorHex = colorHex.toUpperCase(); + + // Check for exact match first + for (int i = 0; i < colorPalette.length; i++) { + if (colorPalette[i].toUpperCase() == normalizedColorHex) { + return i; + } + } + + // If no exact match, find closest color by calculating distance + // Parse RGB values + final hexCode = colorHex.replaceAll('#', ''); + final r = int.parse(hexCode.substring(0, 2), radix: 16); + final g = int.parse(hexCode.substring(2, 4), radix: 16); + final b = int.parse(hexCode.substring(4, 6), radix: 16); + + int closestIndex = 0; + double minDistance = double.infinity; + + for (int i = 0; i < colorPalette.length; i++) { + final paletteHex = colorPalette[i].replaceAll('#', ''); + final pr = int.parse(paletteHex.substring(0, 2), radix: 16); + final pg = int.parse(paletteHex.substring(2, 4), radix: 16); + final pb = int.parse(paletteHex.substring(4, 6), radix: 16); + + // Calculate Euclidean distance in RGB space + final distance = ((r - pr) * (r - pr) + (g - pg) * (g - pg) + (b - pb) * (b - pb)).toDouble(); + + if (distance < minDistance) { + minDistance = distance; + closestIndex = i; + } + } + + return closestIndex; + } + + /// Get color hex from palette index + static String getColorFromIndex(int index) { + if (index < 0 || index >= colorPalette.length) { + return '#9E9E9E'; // Gray for invalid index + } + return colorPalette[index]; + } + /// Create from JSON factory SarTemplate.fromJson(Map json) { return SarTemplate( @@ -90,37 +175,49 @@ class SarTemplate { } /// Convert to SAR message format with placeholder coordinates - /// Example: S:🧑:0,0:Person found + /// New format: S:emoji:colorIndex:0,0:description + /// Example: S:🧑:2:0,0:Person found (2 = Green) String toSarMessage() { + final colorIndex = getColorIndex(); if (description.isNotEmpty) { - return 'S:$emoji:0,0:$description'; + return 'S:$emoji:$colorIndex:0,0:$description'; } - return 'S:$emoji:0,0'; + return 'S:$emoji:$colorIndex:0,0'; } - /// Auto-assign color based on emoji + /// Auto-assign color based on emoji (uses standard color palette) static String _getColorForEmoji(String emoji) { - // Default emoji to color mapping + // Default emoji to color mapping using standard palette final colorMap = { - '🧑': '#4CAF50', // Green - Person - '👤': '#4CAF50', // Green - Person - '🔥': '#F44336', // Red - Fire - '🏕️': '#FF9800', // Orange - Staging - '⛺': '#FF9800', // Orange - Staging - '📦': '#9C27B0', // Purple - Object - '🚁': '#2196F3', // Blue - Helicopter - '🚒': '#F44336', // Red - Fire truck - '🚑': '#F44336', // Red - Ambulance - '⚠️': '#FFC107', // Yellow - Warning - '❌': '#F44336', // Red - Hazard - '✅': '#4CAF50', // Green - Safe - '🏥': '#F44336', // Red - Medical - '💧': '#2196F3', // Blue - Water - '🌲': '#4CAF50', // Green - Forest - '⛰️': '#795548', // Brown - Mountain + // Green (index 2) - Person, Safe, Nature + '🧑': colorPalette[2], + '👤': colorPalette[2], + '✅': colorPalette[2], + '🌲': colorPalette[2], + + // Red (index 0) - Fire, Hazard, Medical, Emergency + '🔥': colorPalette[0], + '🚒': colorPalette[0], + '🚑': colorPalette[0], + '❌': colorPalette[0], + '🏥': colorPalette[0], + + // Orange (index 4) - Staging, Assembly + '🏕️': colorPalette[4], + '⛺': colorPalette[4], + + // Purple (index 5) - Objects + '📦': colorPalette[5], + + // Blue (index 1) - Water, Air support + '🚁': colorPalette[1], + '💧': colorPalette[1], + + // Yellow (index 3) - Warning, Caution + '⚠️': colorPalette[3], }; - return colorMap[emoji] ?? '#9E9E9E'; // Default gray + return colorMap[emoji] ?? '#9E9E9E'; // Default gray for unknown emojis } /// Copy with modifications @@ -156,7 +253,16 @@ class SarTemplate { @override int get hashCode => id.hashCode; - /// Default templates (matches existing SarMarkerType) + /// Default templates (uses standard color palette) + /// Colors reference: + /// - 0 Red (#F44336) - Fire, Hazard, Medical + /// - 1 Blue (#2196F3) - Water, Helicopter + /// - 2 Green (#4CAF50) - Found Person, Safe + /// - 3 Yellow (#FFC107) - Warning + /// - 4 Orange (#FF9800) - Staging Area + /// - 5 Purple (#9C27B0) - Object + /// - 6 Pink (#E91E63) - Reserved + /// - 7 Cyan (#00BCD4) - Reserved static List get defaults { return [ SarTemplate( @@ -164,7 +270,7 @@ class SarTemplate { emoji: '🧑', name: 'Found Person', description: '', - colorHex: '#4CAF50', + colorHex: colorPalette[2], // Green isDefault: true, ), SarTemplate( @@ -172,7 +278,7 @@ class SarTemplate { emoji: '🔥', name: 'Fire', description: '', - colorHex: '#F44336', + colorHex: colorPalette[0], // Red isDefault: true, ), SarTemplate( @@ -180,7 +286,7 @@ class SarTemplate { emoji: '🏕️', name: 'Staging Area', description: '', - colorHex: '#FF9800', + colorHex: colorPalette[4], // Orange isDefault: true, ), SarTemplate( @@ -188,7 +294,7 @@ class SarTemplate { emoji: '📦', name: 'Object', description: '', - colorHex: '#9C27B0', + colorHex: colorPalette[5], // Purple isDefault: true, ), ]; diff --git a/lib/screens/map_tab.dart b/lib/screens/map_tab.dart index 0bfb962..28fb179 100644 --- a/lib/screens/map_tab.dart +++ b/lib/screens/map_tab.dart @@ -878,8 +878,8 @@ class _MapTabState extends State with AutomaticKeepAliveClientMixin { builder: (context) => SarUpdateSheet( prePopulatedPosition: position, allowLocationUpdate: false, // Don't allow changing to current location - onSend: (emoji, name, position, roomPublicKey, sendToChannel) async { - await _sendSarMessage(emoji, name, position, roomPublicKey, sendToChannel); + onSend: (emoji, name, position, roomPublicKey, sendToChannel, colorIndex) async { + await _sendSarMessage(emoji, name, position, roomPublicKey, sendToChannel, colorIndex); }, ), ); @@ -891,6 +891,7 @@ class _MapTabState extends State with AutomaticKeepAliveClientMixin { Position position, Uint8List? roomPublicKey, bool sendToChannel, + int colorIndex, ) async { final connectionProvider = context.read(); final messagesProvider = context.read(); @@ -918,9 +919,9 @@ class _MapTabState extends State with AutomaticKeepAliveClientMixin { } try { - // Format: S::,: + // New format: S:::,: // Round coordinates to 5 decimal places (~1m accuracy) since most GPS is only that accurate - final sarMessage = 'S:$emoji:${position.latitude.toStringAsFixed(5)},${position.longitude.toStringAsFixed(5)}:$name'; + final sarMessage = 'S:$emoji:$colorIndex:${position.latitude.toStringAsFixed(5)},${position.longitude.toStringAsFixed(5)}:$name'; if (sendToChannel) { // Create message ID diff --git a/lib/screens/messages_tab.dart b/lib/screens/messages_tab.dart index e21f1b9..b98ef54 100644 --- a/lib/screens/messages_tab.dart +++ b/lib/screens/messages_tab.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:provider/provider.dart'; import 'package:geolocator/geolocator.dart'; import '../providers/messages_provider.dart'; @@ -64,8 +65,9 @@ class _MessagesTabState extends State { @override void didChangeDependencies() { super.didChangeDependencies(); - // Check for navigation request whenever dependencies change + // Reload saved destination and check for navigation request whenever dependencies change WidgetsBinding.instance.addPostFrameCallback((_) { + _loadSavedDestination(); _checkForNavigationRequest(); }); } @@ -387,13 +389,14 @@ class _MessagesTabState extends State { isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => SarUpdateSheet( - onSend: (emoji, name, position, roomPublicKey, sendToChannel) async { + onSend: (emoji, name, position, roomPublicKey, sendToChannel, colorIndex) async { await _sendSarMessage( emoji, name, position, roomPublicKey, sendToChannel, + colorIndex, ); }, ), @@ -406,6 +409,7 @@ class _MessagesTabState extends State { Position position, Uint8List? roomPublicKey, bool sendToChannel, + int colorIndex, ) async { final connectionProvider = context.read(); final messagesProvider = context.read(); @@ -423,10 +427,10 @@ class _MessagesTabState extends State { } try { - // Format: S::,: + // New format: S:::,: // Round coordinates to 5 decimal places (~1m accuracy) since most GPS is only that accurate final sarMessage = - 'S:$emoji:${position.latitude.toStringAsFixed(5)},${position.longitude.toStringAsFixed(5)}:$name'; + 'S:$emoji:$colorIndex:${position.latitude.toStringAsFixed(5)},${position.longitude.toStringAsFixed(5)}:$name'; if (sendToChannel) { // Create message ID @@ -551,9 +555,51 @@ class _MessagesTabState extends State { } List _getFilteredMessages(MessagesProvider messagesProvider) { - // Show ALL messages regardless of recipient selection - // The recipient selector only controls where NEW messages are sent - return messagesProvider.getRecentMessages(count: 100); + // Get all recent messages + final allMessages = messagesProvider.getRecentMessages(count: 100); + + // If public channel is selected, show ALL messages + if (_destinationType == + MessageDestinationPreferences.destinationTypeChannel && + _selectedRecipient == null) { + return allMessages; + } + + // If a contact or room is selected, filter by recipient + if ((_destinationType == MessageDestinationPreferences.destinationTypeContact || + _destinationType == + MessageDestinationPreferences.destinationTypeRoom) && + _selectedRecipient != null) { + return allMessages.where((message) { + // Include messages sent TO this recipient + if (message.recipientPublicKey != null && + message.recipientPublicKey!.length >= 6 && + _selectedRecipient!.publicKey.length >= 6) { + // Compare first 6 bytes (public key prefix) + final recipientPrefix = message.recipientPublicKey!.sublist(0, 6); + final selectedPrefix = _selectedRecipient!.publicKey.sublist(0, 6); + if (_publicKeysMatch(recipientPrefix, selectedPrefix)) { + return true; + } + } + + // Include messages received FROM this recipient + if (message.senderPublicKeyPrefix != null && + message.senderPublicKeyPrefix!.length >= 6 && + _selectedRecipient!.publicKey.length >= 6) { + final senderPrefix = message.senderPublicKeyPrefix!.sublist(0, 6); + final selectedPrefix = _selectedRecipient!.publicKey.sublist(0, 6); + if (_publicKeysMatch(senderPrefix, selectedPrefix)) { + return true; + } + } + + return false; + }).toList(); + } + + // Default: show all messages (fallback case) + return allMessages; } @override @@ -831,6 +877,8 @@ class _MessageBubble extends StatelessWidget { contact: roomContact, // Include contact for path status logging ); + if (!context.mounted) return; + if (!sentSuccessfully) { messagesProvider.markMessageFailed(retryMessageId); ToastLogger.error(context, 'Failed to resend message'); @@ -845,9 +893,12 @@ class _MessageBubble extends StatelessWidget { messageId: retryMessageId, ); + if (!context.mounted) return; + ToastLogger.info(context, 'Retrying message...'); } } catch (e) { + if (!context.mounted) return; ToastLogger.error(context, 'Retry failed: $e'); } } @@ -899,6 +950,16 @@ class _MessageBubble extends StatelessWidget { ); }, ), + // Share location option (only for SAR markers with GPS coordinates) + if (message.isSarMarker && message.sarGpsCoordinates != null) + ListTile( + leading: const Icon(Icons.share_location), + title: Text(AppLocalizations.of(context)!.shareLocation), + onTap: () { + Navigator.pop(context); + _shareLocation(context); + }, + ), // Delete message option ListTile( leading: const Icon(Icons.delete, color: Colors.red), @@ -982,6 +1043,52 @@ class _MessageBubble extends StatelessWidget { ); } + void _shareLocation(BuildContext context) { + if (message.sarGpsCoordinates == null) { + ToastLogger.error(context, 'No GPS coordinates available'); + return; + } + + final l10n = AppLocalizations.of(context)!; + final coords = message.sarGpsCoordinates!; + + // Get SAR marker type emoji/name + String markerInfo = ''; + if (message.sarMarkerType != null) { + markerInfo = message.sarMarkerType!.emoji; + if (message.sarNotes != null && message.sarNotes!.isNotEmpty) { + markerInfo += ' ${message.sarNotes}'; + } + } else if (message.sarCustomEmoji != null) { + markerInfo = message.sarCustomEmoji!; + if (message.sarNotes != null && message.sarNotes!.isNotEmpty) { + markerInfo += ' ${message.sarNotes}'; + } + } + + // Format coordinates with 6 decimal places (≈0.1m precision) + final lat = coords.latitude.toStringAsFixed(6); + final lon = coords.longitude.toStringAsFixed(6); + + // Build share text + final shareText = l10n.shareLocationText( + markerInfo, + lat, + lon, + 'https://www.google.com/maps/search/?api=1&query=$lat,$lon', + ); + + // Share the location + SharePlus.instance.share( + ShareParams( + text: shareText, + subject: l10n.sarLocationShare, + ), + ); + + ToastLogger.success(context, l10n.locationShared); + } + @override Widget build(BuildContext context) { final isSarMarker = message.isSarMarker; diff --git a/lib/screens/sar_template_management_screen.dart b/lib/screens/sar_template_management_screen.dart index 632abbb..737f1b0 100644 --- a/lib/screens/sar_template_management_screen.dart +++ b/lib/screens/sar_template_management_screen.dart @@ -81,7 +81,7 @@ class _SarTemplateManagementScreenState extends State AlertDialog( title: Text(AppLocalizations.of(context)!.deleteTemplate), content: Text( - AppLocalizations.of(context)!.deleteTemplateConfirmation(template.name), + AppLocalizations.of(context)!.deleteTemplateConfirmation(template.getLocalizedName(context)), ), actions: [ TextButton( @@ -351,7 +351,7 @@ class _TemplateListItem extends StatelessWidget { builder: (context) => AlertDialog( title: Text(AppLocalizations.of(context)!.deleteTemplate), content: Text( - AppLocalizations.of(context)!.deleteTemplateConfirmation(template.name), + AppLocalizations.of(context)!.deleteTemplateConfirmation(template.getLocalizedName(context)), ), actions: [ TextButton( @@ -394,7 +394,7 @@ class _TemplateListItem extends StatelessWidget { title: Row( children: [ Text( - template.name, + template.getLocalizedName(context), style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index d7b11e4..40f21dc 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -178,15 +178,20 @@ class _SettingsScreenState extends State { if (!mounted) return; + // Get localization + final l10n = AppLocalizations.of(context)!; + // Generate sample data final contacts = SampleDataGenerator.generateContacts( centerLocation: centerLocation, + l10n: l10n, teamMemberCount: 5, channelCount: 2, ); final sarMessages = SampleDataGenerator.generateSarMarkerMessages( centerLocation: centerLocation, + l10n: l10n, foundPersonCount: 2, fireCount: 1, stagingCount: 1, @@ -195,6 +200,7 @@ class _SettingsScreenState extends State { final channelMessages = SampleDataGenerator.generateChannelMessages( centerLocation: centerLocation, + l10n: l10n, generalChannelMessages: 8, emergencyChannelMessages: 5, ); diff --git a/lib/utils/sample_data_generator.dart b/lib/utils/sample_data_generator.dart index 64d513f..04cd97e 100644 --- a/lib/utils/sample_data_generator.dart +++ b/lib/utils/sample_data_generator.dart @@ -5,6 +5,7 @@ import '../models/contact.dart'; import '../models/contact_telemetry.dart'; import '../models/message.dart'; import '../models/sar_marker.dart'; +import '../l10n/app_localizations.dart'; /// Generates sample data for testing/demo purposes class SampleDataGenerator { @@ -13,6 +14,7 @@ class SampleDataGenerator { /// Generate sample contacts around a center location static List generateContacts({ required LatLng centerLocation, + required AppLocalizations l10n, int teamMemberCount = 5, int channelCount = 2, }) { @@ -20,21 +22,21 @@ class SampleDataGenerator { final now = DateTime.now(); final teamNames = [ - '👮Police Lead', - '🚁Drone Operator', - '🧑🏻‍🚒Firefighter Alpha', - '🧑‍⚕️Medic Charlie', - '📡Command Delta', - '🚒Fire Engine', - '👨‍✈️Air Support', - '🧑‍💼Base Coordinator', + '👮${l10n.samplePoliceLead}', + '🚁${l10n.sampleDroneOperator}', + '🧑🏻‍🚒${l10n.sampleFirefighterAlpha}', + '🧑‍⚕️${l10n.sampleMedicCharlie}', + '📡${l10n.sampleCommandDelta}', + '🚒${l10n.sampleFireEngine}', + '👨‍✈️${l10n.sampleAirSupport}', + '🧑‍💼${l10n.sampleBaseCoordinator}', ]; final channelNames = [ - 'General', - 'Emergency', - 'Coordination', - 'Updates', + l10n.general, + l10n.channelEmergency, + l10n.channelCoordination, + l10n.channelUpdates, ]; // Generate team members (chat contacts) @@ -114,6 +116,7 @@ class SampleDataGenerator { /// Generate sample SAR markers around a center location static List generateSarMarkerMessages({ required LatLng centerLocation, + required AppLocalizations l10n, int foundPersonCount = 2, int fireCount = 1, int stagingCount = 1, @@ -147,7 +150,7 @@ class SampleDataGenerator { isSarMarker: true, sarMarkerType: SarMarkerType.foundPerson, sarGpsCoordinates: LatLng(lat, lon), - senderName: 'Sample Team Member', + senderName: l10n.sampleTeamMember, )); messageId++; } @@ -176,7 +179,7 @@ class SampleDataGenerator { isSarMarker: true, sarMarkerType: SarMarkerType.fire, sarGpsCoordinates: LatLng(lat, lon), - senderName: 'Sample Scout', + senderName: l10n.sampleScout, )); messageId++; } @@ -205,7 +208,7 @@ class SampleDataGenerator { isSarMarker: true, sarMarkerType: SarMarkerType.stagingArea, sarGpsCoordinates: LatLng(lat, lon), - senderName: 'Sample Base', + senderName: l10n.sampleBase, )); messageId++; } @@ -223,10 +226,10 @@ class SampleDataGenerator { final timestamp = now.subtract(Duration(minutes: 40 + i * 5)); final notes = [ - ' Backpack found - blue color', - ' Vehicle abandoned - check for owner', - ' Camping equipment discovered', - ' Trail marker found off-path', + l10n.sampleObjectBackpack, + l10n.sampleObjectVehicle, + l10n.sampleObjectCamping, + l10n.sampleObjectTrailMarker, ]; messages.add(Message( @@ -241,7 +244,7 @@ class SampleDataGenerator { isSarMarker: true, sarMarkerType: SarMarkerType.object, sarGpsCoordinates: LatLng(lat, lon), - senderName: 'Sample Searcher', + senderName: l10n.sampleSearcher, )); messageId++; } @@ -252,6 +255,7 @@ class SampleDataGenerator { /// Generate sample channel messages for public channels static List generateChannelMessages({ LatLng? centerLocation, + required AppLocalizations l10n, int generalChannelMessages = 8, int emergencyChannelMessages = 5, }) { @@ -263,44 +267,44 @@ class SampleDataGenerator { // Sample messages for General channel (index 0) final generalMessages = [ - 'All teams check in', - 'Weather update: Clear skies, temp 18°C', - 'Base camp established at staging area', - 'Team Alpha moving to sector 2', - 'Radio check - all stations respond', - 'Water supply available at checkpoint 3', - 'Team Bravo reporting: sector 1 clear', - 'ETA to rally point: 15 minutes', - 'Supply drop confirmed for 14:00', - 'Drone survey completed - no findings', - 'Team Charlie requesting backup', - 'All units: maintain radio discipline', + l10n.sampleMsgAllTeamsCheckIn, + l10n.sampleMsgWeatherUpdate, + l10n.sampleMsgBaseCamp, + l10n.sampleMsgTeamAlpha, + l10n.sampleMsgRadioCheck, + l10n.sampleMsgWaterSupply, + l10n.sampleMsgTeamBravo, + l10n.sampleMsgEtaRallyPoint, + l10n.sampleMsgSupplyDrop, + l10n.sampleMsgDroneSurvey, + l10n.sampleMsgTeamCharlie, + l10n.sampleMsgRadioDiscipline, ]; // Sample messages for Emergency channel (index 1) // Mix regular messages and SAR markers final emergencyMessages = [ - 'URGENT: Medical assistance needed at sector 4', - 'S:🧑:${center.latitude.toStringAsFixed(5)},${(center.longitude + 0.005).toStringAsFixed(5)} Adult male, conscious', - 'Fire spotted - coordinates incoming', - 'S:🔥:${(center.latitude + 0.008).toStringAsFixed(5)},${(center.longitude + 0.003).toStringAsFixed(5)} Spreading rapidly!', - 'PRIORITY: Need helicopter support', - 'Medical team en route to your location', - 'Evac helicopter ETA 10 minutes', - 'Emergency resolved - all clear', - 'S:🏕️:${(center.latitude - 0.002).toStringAsFixed(5)},${(center.longitude - 0.004).toStringAsFixed(5)} Emergency staging area', - 'Emergency services notified and responding', + l10n.sampleMsgUrgentMedical, + 'S:🧑:${center.latitude.toStringAsFixed(5)},${(center.longitude + 0.005).toStringAsFixed(5)}${l10n.sampleMsgAdultMale}', + l10n.sampleMsgFireSpotted, + 'S:🔥:${(center.latitude + 0.008).toStringAsFixed(5)},${(center.longitude + 0.003).toStringAsFixed(5)}${l10n.sampleMsgSpreadingRapidly}', + l10n.sampleMsgPriorityHelicopter, + l10n.sampleMsgMedicalTeamEnRoute, + l10n.sampleMsgEvacHelicopter, + l10n.sampleMsgEmergencyResolved, + 'S:🏕️:${(center.latitude - 0.002).toStringAsFixed(5)},${(center.longitude - 0.004).toStringAsFixed(5)}${l10n.sampleMsgEmergencyStagingArea}', + l10n.sampleMsgEmergencyServices, ]; final teamNames = [ - 'Alpha Team Lead', - 'Bravo Scout', - 'Charlie Medic', - 'Delta Navigator', - 'Echo Support', - 'Base Command', - 'Field Coordinator', - 'Medical Team', + l10n.sampleAlphaTeamLead, + l10n.sampleBravoScout, + l10n.sampleCharlieMedic, + l10n.sampleDeltaNavigator, + l10n.sampleEchoSupport, + l10n.sampleBaseCommand, + l10n.sampleFieldCoordinator, + l10n.sampleMedicalTeam, ]; // Generate General channel messages diff --git a/lib/utils/sar_message_parser.dart b/lib/utils/sar_message_parser.dart index 4d4ded1..c7a8fe8 100644 --- a/lib/utils/sar_message_parser.dart +++ b/lib/utils/sar_message_parser.dart @@ -3,16 +3,23 @@ import '../models/sar_marker.dart'; import '../models/message.dart'; /// Parser for SAR (Search & Rescue) special messages -/// Format: S::,: +/// Old format: S::,: +/// New format: S:::,: /// Examples: -/// S:🧑:37.7749,-122.4194 -/// S:🔥:40.7128,-74.0060:Large wildfire spreading -/// S:🏕️:34.0522,-118.2437:Base camp established +/// S:🧑:37.7749,-122.4194 (old format) +/// S:🧑:2:37.7749,-122.4194 (new format with green color) +/// S:🔥:0:40.7128,-74.0060:Large wildfire spreading (new format with red color) class SarMessageParser { - // Updated regex to capture optional message after coordinates - // Captures: emoji (one or more non-colon chars), latitude, longitude, optional message - // Note: Emojis are multi-byte characters, so we use [^:]+ instead of . - static final RegExp _sarPattern = RegExp( + // Regex for new format with color index: S:emoji:colorIndex:lat,lon:notes + // Captures: emoji, colorIndex (single digit), latitude, longitude, optional message + static final RegExp _sarPatternNew = RegExp( + r'^S:([^:]+):(\d):(-?\d+\.?\d*),(-?\d+\.?\d*):?(.*)', + multiLine: false, + ); + + // Regex for old format (backward compatibility): S:emoji:lat,lon:notes + // Captures: emoji, latitude, longitude, optional message + static final RegExp _sarPatternOld = RegExp( r'^S:([^:]+):(-?\d+\.?\d*),(-?\d+\.?\d*):?(.*)', multiLine: false, ); @@ -21,30 +28,61 @@ class SarMessageParser { static bool isSarMessage(String text) { // Extract just the first line for matching final firstLine = text.trim().split('\n').first; - return firstLine.startsWith('S:') && _sarPattern.hasMatch(firstLine); + return firstLine.startsWith('S:') && (_sarPatternNew.hasMatch(firstLine) || _sarPatternOld.hasMatch(firstLine)); } /// Parse a SAR message and extract marker information /// Returns null if the message is not a valid SAR message + /// Supports both old format (S:emoji:lat,lon:notes) and new format (S:emoji:colorIndex:lat,lon:notes) static SarMarkerInfo? parse(String text) { final trimmed = text.trim(); if (!trimmed.startsWith('S:')) return null; // Extract first line (actual SAR marker) final firstLine = trimmed.split('\n').first; - final match = _sarPattern.firstMatch(firstLine); - if (match == null) return null; + + // Try new format first (with color index) + var match = _sarPatternNew.firstMatch(firstLine); + bool isNewFormat = match != null; + + // If new format didn't match, try old format + if (match == null) { + match = _sarPatternOld.firstMatch(firstLine); + if (match == null) return null; + } try { - final emoji = match.group(1)!; - final latitude = double.parse(match.group(2)!); - final longitude = double.parse(match.group(3)!); - final inlineMessage = match.group(4)?.trim(); // Optional message after colon + String emoji; + double latitude; + double longitude; + String? inlineMessage; + int? colorIndex; + + if (isNewFormat) { + // New format: S:emoji:colorIndex:lat,lon:notes + emoji = match!.group(1)!; + colorIndex = int.parse(match.group(2)!); + latitude = double.parse(match.group(3)!); + longitude = double.parse(match.group(4)!); + inlineMessage = match.group(5)?.trim(); + } else { + // Old format: S:emoji:lat,lon:notes + emoji = match!.group(1)!; + colorIndex = null; // No color index in old format + latitude = double.parse(match.group(2)!); + longitude = double.parse(match.group(3)!); + inlineMessage = match.group(4)?.trim(); + } // Validate coordinates if (latitude < -90 || latitude > 90) return null; if (longitude < -180 || longitude > 180) return null; + // Validate color index if present + if (colorIndex != null && (colorIndex < 0 || colorIndex > 7)) { + colorIndex = null; // Invalid index, ignore it + } + final markerType = SarMarkerType.fromEmoji(emoji); final location = LatLng(latitude, longitude); @@ -65,6 +103,7 @@ class SarMessageParser { location: location, emoji: emoji, notes: notes, + colorIndex: colorIndex, ); } catch (e) { return null; @@ -84,16 +123,20 @@ class SarMessageParser { sarCustomEmoji: sarInfo.type == SarMarkerType.unknown ? sarInfo.emoji // Preserve custom emoji for unknown types : null, + sarColorIndex: sarInfo.colorIndex, // Store color index ); } - /// Create a SAR marker message text + /// Create a SAR marker message text (new format with color index) static String createSarMessage({ required SarMarkerType type, required LatLng location, String? notes, + int? colorIndex, }) { - final text = 'S:${type.emoji}:${location.latitude},${location.longitude}'; + // New format: S:emoji:colorIndex:lat,lon:notes + final colorIdx = colorIndex ?? 0; // Default to red if not specified + final text = 'S:${type.emoji}:$colorIdx:${location.latitude},${location.longitude}'; if (notes != null && notes.isNotEmpty) { // Use colon-separated format for inline message return '$text:$notes'; @@ -166,16 +209,18 @@ class SarMarkerInfo { final LatLng location; final String emoji; final String? notes; + final int? colorIndex; // Color index from standard palette (0-7), null for backward compatibility SarMarkerInfo({ required this.type, required this.location, required this.emoji, this.notes, + this.colorIndex, }); @override String toString() { - return 'SarMarkerInfo(type: ${type.displayName}, location: $location, notes: $notes)'; + return 'SarMarkerInfo(type: ${type.displayName}, location: $location, colorIndex: $colorIndex, notes: $notes)'; } } diff --git a/lib/widgets/contacts/direct_message_sheet.dart b/lib/widgets/contacts/direct_message_sheet.dart index 77f0cee..1fe904d 100644 --- a/lib/widgets/contacts/direct_message_sheet.dart +++ b/lib/widgets/contacts/direct_message_sheet.dart @@ -9,6 +9,7 @@ import '../../models/message.dart'; import '../../providers/connection_provider.dart'; import '../../providers/messages_provider.dart'; import '../../providers/app_provider.dart'; +import '../../services/message_destination_preferences.dart'; import '../../utils/toast_logger.dart'; import '../../l10n/app_localizations.dart'; @@ -159,6 +160,15 @@ class _DirectMessageSheetState extends State { messagesProvider.markMessageFailed(messageId); } + // Save the recipient to preferences so messages tab filters to this contact + final recipientType = widget.contact.type == ContactType.room + ? MessageDestinationPreferences.destinationTypeRoom + : MessageDestinationPreferences.destinationTypeContact; + await MessageDestinationPreferences.setDestination( + recipientType, + recipientPublicKey: widget.contact.publicKeyHex, + ); + _textController.clear(); _focusNode.unfocus(); diff --git a/lib/widgets/map_markers.dart b/lib/widgets/map_markers.dart index c35e038..ff6e368 100644 --- a/lib/widgets/map_markers.dart +++ b/lib/widgets/map_markers.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import '../models/contact.dart'; import '../models/sar_marker.dart'; +import '../models/sar_template.dart'; import '../l10n/app_localizations.dart'; class MapMarkers { @@ -129,7 +130,7 @@ class MapMarkers { Container( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), decoration: BoxDecoration( - color: _getSarMarkerColor(marker.type), + color: _getSarMarkerColor(marker), borderRadius: BorderRadius.circular(3), ), child: Text( @@ -145,7 +146,7 @@ class MapMarkers { // Marker emoji/icon Container( decoration: BoxDecoration( - color: _getSarMarkerColor(marker.type), + color: _getSarMarkerColor(marker), shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), boxShadow: [ @@ -302,8 +303,16 @@ class MapMarkers { return Colors.red; // Stale } - static Color _getSarMarkerColor(SarMarkerType type) { - switch (type) { + static Color _getSarMarkerColor(SarMarker marker) { + // If marker has a color index, use it (new format) + if (marker.colorIndex != null && marker.colorIndex! >= 0 && marker.colorIndex! < 8) { + final colorHex = SarTemplate.getColorFromIndex(marker.colorIndex!); + final hexCode = colorHex.replaceAll('#', ''); + return Color(int.parse('FF$hexCode', radix: 16)); + } + + // Otherwise fall back to type-based colors (old format or backward compatibility) + switch (marker.type) { case SarMarkerType.foundPerson: return Colors.green; case SarMarkerType.fire: diff --git a/lib/widgets/messages/sar_update_sheet.dart b/lib/widgets/messages/sar_update_sheet.dart index cb19e4d..f5a55d9 100644 --- a/lib/widgets/messages/sar_update_sheet.dart +++ b/lib/widgets/messages/sar_update_sheet.dart @@ -18,6 +18,7 @@ class SarUpdateSheet extends StatefulWidget { Position, Uint8List?, bool, + int colorIndex, ) onSend; final Position? prePopulatedPosition; @@ -784,7 +785,7 @@ class _SarUpdateSheetState extends State { displayText = _selectedTemplate!.name; } - // Send SAR marker with emoji and display text + // Send SAR marker with emoji, display text, and color index await widget.onSend( _selectedTemplate!.emoji, displayText, @@ -793,6 +794,7 @@ class _SarUpdateSheetState extends State { ? null : _selectedContact!.publicKey, _selectedContact!.isChannel, + _selectedTemplate!.getColorIndex(), // Include color index ); if (context.mounted) { Navigator.pop(context); @@ -869,7 +871,7 @@ class TemplateChip extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - template.name, + template.getLocalizedName(context), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600,