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.
This commit is contained in:
Janez T
2025-10-23 19:17:13 +02:00
parent b70eed1bf2
commit 98cda8c976
28 changed files with 2734 additions and 270 deletions

View File

@@ -30,7 +30,8 @@
"Bash(git --no-pager diff:*)", "Bash(git --no-pager diff:*)",
"Bash(git add:*)", "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 <noreply@anthropic.com>\nEOF\n)\")", "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 <noreply@anthropic.com>\nEOF\n)\")",
"Bash(git --no-pager log -1 --stat)" "Bash(git --no-pager log -1 --stat)",
"Bash(awk:*)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@@ -1752,6 +1752,10 @@
"textCopiedToClipboard": "Text in Zwischenablage kopiert", "textCopiedToClipboard": "Text in Zwischenablage kopiert",
"deleteMessage": "Nachricht löschen", "deleteMessage": "Nachricht löschen",
"deleteMessageConfirmation": "Möchten Sie diese Nachricht wirklich 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": "Kontakte aktualisiert",
"@refreshedContacts": { "@refreshedContacts": {
@@ -2326,12 +2330,12 @@
} }
}, },
"sarTemplates": "SAR Templates", "sarTemplates": "SAR-Vorlagen",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "SAR-Vorlagen verwalten",
"addTemplate": "Add Template", "addTemplate": "Vorlage hinzufügen",
"editTemplate": "Edit Template", "editTemplate": "Vorlage bearbeiten",
"deleteTemplate": "Delete Template", "deleteTemplate": "Vorlage löschen",
"templateName": "Template Name", "templateName": "Vorlagenname",
"templateNameHint": "e.g. Found Person", "templateNameHint": "e.g. Found Person",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Emoji ist erforderlich", "emojiRequired": "Emoji ist erforderlich",
@@ -2340,8 +2344,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Importieren",
"exportToClipboard": "Export", "exportToClipboard": "Exportieren",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -2350,10 +2354,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Auf Standard zurücksetzen",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "Dadurch werden alle benutzerdefinierten Vorlagen gelöscht und die 4 Standardvorlagen wiederhergestellt. Fortfahren?",
"reset": "Reset", "reset": "Zurücksetzen",
"resetComplete": "Templates reset to defaults", "resetComplete": "Vorlagen auf Standard zurückgesetzt",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -2382,5 +2386,55 @@
"noContactsOrRoomsAvailable": "Keine Kontakte oder Räume verfügbar", "noContactsOrRoomsAvailable": "Keine Kontakte oder Räume verfügbar",
"messagesWillBeSentToPublicChannel": "Nachrichten werden an öffentlichen Kanal gesendet", "messagesWillBeSentToPublicChannel": "Nachrichten werden an öffentlichen Kanal gesendet",
"newMessage": "Neue Nachricht", "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"
} }

View File

@@ -1768,6 +1768,40 @@
"description": "Confirmation text for message deletion" "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": "Refreshed contacts",
"@refreshedContacts": { "@refreshedContacts": {
"description": "Success message when contacts are refreshed" "description": "Success message when contacts are refreshed"
@@ -2639,5 +2673,250 @@
"channel": "Channel", "channel": "Channel",
"@channel": { "@channel": {
"description": "Channel label in notifications" "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"
} }
} }

View File

@@ -1752,6 +1752,10 @@
"textCopiedToClipboard": "Texto copiado al portapapeles", "textCopiedToClipboard": "Texto copiado al portapapeles",
"deleteMessage": "Eliminar mensaje", "deleteMessage": "Eliminar mensaje",
"deleteMessageConfirmation": "¿Está seguro de que desea eliminar este 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": "Contactos actualizados",
"@refreshedContacts": { "@refreshedContacts": {
@@ -2321,12 +2325,12 @@
} }
}, },
"sarTemplates": "SAR Templates", "sarTemplates": "Plantillas SAR",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "Gestionar plantillas SAR",
"addTemplate": "Add Template", "addTemplate": "Agregar plantilla",
"editTemplate": "Edit Template", "editTemplate": "Editar plantilla",
"deleteTemplate": "Delete Template", "deleteTemplate": "Eliminar plantilla",
"templateName": "Template Name", "templateName": "Nombre de plantilla",
"templateNameHint": "e.g. Found Person", "templateNameHint": "e.g. Found Person",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Se requiere emoji", "emojiRequired": "Se requiere emoji",
@@ -2335,8 +2339,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Importar",
"exportToClipboard": "Export", "exportToClipboard": "Exportar",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -2345,10 +2349,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Restablecer valores predeterminados",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "Esto eliminará todas las plantillas personalizadas y restaurará las 4 plantillas predeterminadas. ¿Continuar?",
"reset": "Reset", "reset": "Restablecer",
"resetComplete": "Templates reset to defaults", "resetComplete": "Plantillas restablecidas a valores predeterminados",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -2377,5 +2381,55 @@
"noContactsOrRoomsAvailable": "No hay contactos o salas disponibles", "noContactsOrRoomsAvailable": "No hay contactos o salas disponibles",
"messagesWillBeSentToPublicChannel": "Los mensajes se enviarán al canal público", "messagesWillBeSentToPublicChannel": "Los mensajes se enviarán al canal público",
"newMessage": "Nuevo mensaje", "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"
} }

View File

@@ -1752,6 +1752,10 @@
"textCopiedToClipboard": "Texte copié dans le presse-papiers", "textCopiedToClipboard": "Texte copié dans le presse-papiers",
"deleteMessage": "Supprimer le message", "deleteMessage": "Supprimer le message",
"deleteMessageConfirmation": "Êtes-vous sûr de vouloir supprimer ce 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": "Contacts actualisés",
"@refreshedContacts": { "@refreshedContacts": {
@@ -2326,12 +2330,12 @@
} }
}, },
"sarTemplates": "SAR Templates", "sarTemplates": "Modèles SAR",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "Gérer les modèles SAR",
"addTemplate": "Add Template", "addTemplate": "Ajouter un modèle",
"editTemplate": "Edit Template", "editTemplate": "Modifier le modèle",
"deleteTemplate": "Delete Template", "deleteTemplate": "Supprimer le modèle",
"templateName": "Template Name", "templateName": "Nom du modèle",
"templateNameHint": "e.g. Found Person", "templateNameHint": "e.g. Found Person",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Emoji est requis", "emojiRequired": "Emoji est requis",
@@ -2340,8 +2344,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Importer",
"exportToClipboard": "Export", "exportToClipboard": "Exporter",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -2350,10 +2354,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Réinitialiser aux valeurs par défaut",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "Cela supprimera tous les modèles personnalisés et restaurera les 4 modèles par défaut. Continuer?",
"reset": "Reset", "reset": "Réinitialiser",
"resetComplete": "Templates reset to defaults", "resetComplete": "Modèles réinitialisés aux valeurs par défaut",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -2382,5 +2386,55 @@
"noContactsOrRoomsAvailable": "Aucun contact ou salle disponible", "noContactsOrRoomsAvailable": "Aucun contact ou salle disponible",
"messagesWillBeSentToPublicChannel": "Les messages seront envoyés au canal public", "messagesWillBeSentToPublicChannel": "Les messages seront envoyés au canal public",
"newMessage": "Nouveau message", "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"
} }

View File

@@ -620,6 +620,10 @@
"textCopiedToClipboard": "Tekst kopiran u međuspremnik", "textCopiedToClipboard": "Tekst kopiran u međuspremnik",
"deleteMessage": "Izbriši poruku", "deleteMessage": "Izbriši poruku",
"deleteMessageConfirmation": "Jeste li sigurni da želite izbrisati ovu 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", "refreshedContacts": "Kontakti osvježeni",
@@ -790,13 +794,13 @@
"failedToGetLocation": "Neuspjelo dohvaćanje lokacije: {error}", "failedToGetLocation": "Neuspjelo dohvaćanje lokacije: {error}",
"sarTemplates": "SAR Templates", "sarTemplates": "SAR predlošci",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "Upravljanje SAR predlošcima",
"addTemplate": "Add Template", "addTemplate": "Dodaj predložak",
"editTemplate": "Edit Template", "editTemplate": "Uredi predložak",
"deleteTemplate": "Delete Template", "deleteTemplate": "Izbriši predložak",
"templateName": "Template Name", "templateName": "Naziv predloška",
"templateNameHint": "e.g. Found Person", "templateNameHint": "npr. Pronađena osoba",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Emoji je obavezan", "emojiRequired": "Emoji je obavezan",
"nameRequired": "Ime je obavezno", "nameRequired": "Ime je obavezno",
@@ -804,8 +808,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Uvezi",
"exportToClipboard": "Export", "exportToClipboard": "Izvezi",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -814,10 +818,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Vrati na zadane",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "Ovo će izbrisati sve prilagođene predloške i vratiti 4 zadana predloška. Nastaviti?",
"reset": "Reset", "reset": "Vrati",
"resetComplete": "Templates reset to defaults", "resetComplete": "Predlošci vraćeni na zadane",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -846,5 +850,55 @@
"noContactsOrRoomsAvailable": "Nema dostupnih kontakata ili soba", "noContactsOrRoomsAvailable": "Nema dostupnih kontakata ili soba",
"messagesWillBeSentToPublicChannel": "Poruke će biti poslane na javni kanal", "messagesWillBeSentToPublicChannel": "Poruke će biti poslane na javni kanal",
"newMessage": "Nova poruka", "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"
} }

View File

@@ -1752,6 +1752,10 @@
"textCopiedToClipboard": "Testo copiato negli appunti", "textCopiedToClipboard": "Testo copiato negli appunti",
"deleteMessage": "Elimina messaggio", "deleteMessage": "Elimina messaggio",
"deleteMessageConfirmation": "Sei sicuro di voler eliminare questo 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": "Contatti aggiornati",
"@refreshedContacts": { "@refreshedContacts": {
@@ -2326,12 +2330,12 @@
} }
}, },
"sarTemplates": "SAR Templates", "sarTemplates": "Modelli SAR",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "Gestisci modelli SAR",
"addTemplate": "Add Template", "addTemplate": "Aggiungi modello",
"editTemplate": "Edit Template", "editTemplate": "Modifica modello",
"deleteTemplate": "Delete Template", "deleteTemplate": "Elimina modello",
"templateName": "Template Name", "templateName": "Nome modello",
"templateNameHint": "e.g. Found Person", "templateNameHint": "e.g. Found Person",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Emoji è obbligatorio", "emojiRequired": "Emoji è obbligatorio",
@@ -2340,8 +2344,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Importa",
"exportToClipboard": "Export", "exportToClipboard": "Esporta",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -2350,10 +2354,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Ripristina predefiniti",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "Questo eliminerà tutti i modelli personalizzati e ripristinerà i 4 modelli predefiniti. Continuare?",
"reset": "Reset", "reset": "Ripristina",
"resetComplete": "Templates reset to defaults", "resetComplete": "Modelli ripristinati ai valori predefiniti",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -2382,5 +2386,55 @@
"noContactsOrRoomsAvailable": "Nessun contatto o stanza disponibile", "noContactsOrRoomsAvailable": "Nessun contatto o stanza disponibile",
"messagesWillBeSentToPublicChannel": "I messaggi saranno inviati al canale pubblico", "messagesWillBeSentToPublicChannel": "I messaggi saranno inviati al canale pubblico",
"newMessage": "Nuovo messaggio", "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"
} }

View File

@@ -1907,6 +1907,35 @@ abstract class AppLocalizations {
/// **'Are you sure you want to delete this message?'** /// **'Are you sure you want to delete this message?'**
String get deleteMessageConfirmation; 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 /// Success message when contacts are refreshed
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@@ -2806,6 +2835,300 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Channel'** /// **'Channel'**
String get 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 class _AppLocalizationsDelegate

View File

@@ -1041,6 +1041,25 @@ class AppLocalizationsDe extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Möchten Sie diese Nachricht wirklich löschen?'; '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 @override
String get refreshedContacts => 'Kontakte aktualisiert'; String get refreshedContacts => 'Kontakte aktualisiert';
@@ -1379,22 +1398,22 @@ class AppLocalizationsDe extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'SAR-Vorlagen';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'SAR-Vorlagen verwalten';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Vorlage hinzufügen';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Vorlage bearbeiten';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Vorlage löschen';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Vorlagenname';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'e.g. Found Person';
@@ -1421,10 +1440,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Importieren';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Exportieren';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1464,17 +1483,17 @@ class AppLocalizationsDe extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Auf Standard zurücksetzen';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Zurücksetzen';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete => 'Vorlagen auf Standard zurückgesetzt';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1561,4 +1580,162 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get channel => 'Kanal'; 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';
} }

View File

@@ -1031,6 +1031,25 @@ class AppLocalizationsEn extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Are you sure you want to delete this message?'; '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 @override
String get refreshedContacts => 'Refreshed contacts'; String get refreshedContacts => 'Refreshed contacts';
@@ -1545,4 +1564,154 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get channel => 'Channel'; 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';
} }

View File

@@ -1037,6 +1037,25 @@ class AppLocalizationsEs extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'¿Está seguro de que desea eliminar este mensaje?'; '¿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 @override
String get refreshedContacts => 'Contactos actualizados'; String get refreshedContacts => 'Contactos actualizados';
@@ -1374,22 +1393,22 @@ class AppLocalizationsEs extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'Plantillas SAR';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'Gestionar plantillas SAR';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Agregar plantilla';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Editar plantilla';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Eliminar plantilla';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Nombre de plantilla';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'e.g. Found Person';
@@ -1416,10 +1435,10 @@ class AppLocalizationsEs extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Importar';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Exportar';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1459,17 +1478,18 @@ class AppLocalizationsEs extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Restablecer valores predeterminados';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Restablecer';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete =>
'Plantillas restablecidas a valores predeterminados';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1556,4 +1576,167 @@ class AppLocalizationsEs extends AppLocalizations {
@override @override
String get channel => 'Canal'; 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';
} }

View File

@@ -1042,6 +1042,25 @@ class AppLocalizationsFr extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Êtes-vous sûr de vouloir supprimer ce message?'; 'Ê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 @override
String get refreshedContacts => 'Contacts actualisés'; String get refreshedContacts => 'Contacts actualisés';
@@ -1382,22 +1401,22 @@ class AppLocalizationsFr extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'Modèles SAR';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'Gérer les modèles SAR';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Ajouter un modèle';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Modifier le modèle';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Supprimer le modèle';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Nom du modèle';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'e.g. Found Person';
@@ -1424,10 +1443,10 @@ class AppLocalizationsFr extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Importer';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Exporter';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1467,17 +1486,17 @@ class AppLocalizationsFr extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Réinitialiser aux valeurs par défaut';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Réinitialiser';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete => 'Modèles réinitialisés aux valeurs par défaut';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1564,4 +1583,166 @@ class AppLocalizationsFr extends AppLocalizations {
@override @override
String get channel => 'Canal'; 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';
} }

View File

@@ -1033,6 +1033,25 @@ class AppLocalizationsHr extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Jeste li sigurni da želite izbrisati ovu poruku?'; '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 @override
String get refreshedContacts => 'Kontakti osvježeni'; String get refreshedContacts => 'Kontakti osvježeni';
@@ -1367,25 +1386,25 @@ class AppLocalizationsHr extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'SAR predlošci';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'Upravljanje SAR predlošcima';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Dodaj predložak';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Uredi predložak';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Izbriši predložak';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Naziv predloška';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'npr. Pronađena osoba';
@override @override
String get templateEmoji => 'Emoji'; String get templateEmoji => 'Emoji';
@@ -1409,10 +1428,10 @@ class AppLocalizationsHr extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Uvezi';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Izvezi';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1452,17 +1471,17 @@ class AppLocalizationsHr extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Vrati na zadane';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Vrati';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete => 'Predlošci vraćeni na zadane';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1548,4 +1567,159 @@ class AppLocalizationsHr extends AppLocalizations {
@override @override
String get channel => 'Kanal'; 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';
} }

View File

@@ -1039,6 +1039,25 @@ class AppLocalizationsIt extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Sei sicuro di voler eliminare questo messaggio?'; '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 @override
String get refreshedContacts => 'Contatti aggiornati'; String get refreshedContacts => 'Contatti aggiornati';
@@ -1377,22 +1396,22 @@ class AppLocalizationsIt extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'Modelli SAR';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'Gestisci modelli SAR';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Aggiungi modello';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Modifica modello';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Elimina modello';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Nome modello';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'e.g. Found Person';
@@ -1419,10 +1438,10 @@ class AppLocalizationsIt extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Importa';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Esporta';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1462,17 +1481,17 @@ class AppLocalizationsIt extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Ripristina predefiniti';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Ripristina';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete => 'Modelli ripristinati ai valori predefiniti';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1558,4 +1577,164 @@ class AppLocalizationsIt extends AppLocalizations {
@override @override
String get channel => 'Canale'; 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';
} }

View File

@@ -1033,6 +1033,25 @@ class AppLocalizationsSl extends AppLocalizations {
String get deleteMessageConfirmation => String get deleteMessageConfirmation =>
'Ali ste prepričani, da želite izbrisati to sporočilo?'; '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 @override
String get refreshedContacts => 'Stiki osveženi'; String get refreshedContacts => 'Stiki osveženi';
@@ -1370,25 +1389,25 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get sarTemplates => 'SAR Templates'; String get sarTemplates => 'SAR predloge';
@override @override
String get manageSarTemplates => 'Manage cursor on target templates'; String get manageSarTemplates => 'Upravljanje SAR predlog';
@override @override
String get addTemplate => 'Add Template'; String get addTemplate => 'Dodaj predlogo';
@override @override
String get editTemplate => 'Edit Template'; String get editTemplate => 'Uredi predlogo';
@override @override
String get deleteTemplate => 'Delete Template'; String get deleteTemplate => 'Izbriši predlogo';
@override @override
String get templateName => 'Template Name'; String get templateName => 'Ime predloge';
@override @override
String get templateNameHint => 'e.g. Found Person'; String get templateNameHint => 'npr. Najdena oseba';
@override @override
String get templateEmoji => 'Emoji'; String get templateEmoji => 'Emoji';
@@ -1412,10 +1431,10 @@ class AppLocalizationsSl extends AppLocalizations {
String get previewFormat => 'Preview (SAR Message Format)'; String get previewFormat => 'Preview (SAR Message Format)';
@override @override
String get importFromClipboard => 'Import'; String get importFromClipboard => 'Uvozi';
@override @override
String get exportToClipboard => 'Export'; String get exportToClipboard => 'Izvozi';
@override @override
String deleteTemplateConfirmation(String name) { String deleteTemplateConfirmation(String name) {
@@ -1455,17 +1474,17 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get resetToDefaults => 'Reset to Defaults'; String get resetToDefaults => 'Ponastavi na privzeto';
@override @override
String get resetToDefaultsConfirmation => 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 @override
String get reset => 'Reset'; String get reset => 'Ponastavi';
@override @override
String get resetComplete => 'Templates reset to defaults'; String get resetComplete => 'Predloge ponastavljene na privzeto';
@override @override
String get noTemplates => 'No templates available'; String get noTemplates => 'No templates available';
@@ -1550,4 +1569,160 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get channel => 'Kanal'; 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';
} }

View File

@@ -620,6 +620,10 @@
"textCopiedToClipboard": "Besedilo kopirano v odložišče", "textCopiedToClipboard": "Besedilo kopirano v odložišče",
"deleteMessage": "Izbriši sporočilo", "deleteMessage": "Izbriši sporočilo",
"deleteMessageConfirmation": "Ali ste prepričani, da želite izbrisati to 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", "refreshedContacts": "Stiki osveženi",
@@ -790,13 +794,13 @@
"failedToGetLocation": "Pridobivanje lokacije ni uspelo: {error}", "failedToGetLocation": "Pridobivanje lokacije ni uspelo: {error}",
"sarTemplates": "SAR Templates", "sarTemplates": "SAR predloge",
"manageSarTemplates": "Manage cursor on target templates", "manageSarTemplates": "Upravljanje SAR predlog",
"addTemplate": "Add Template", "addTemplate": "Dodaj predlogo",
"editTemplate": "Edit Template", "editTemplate": "Uredi predlogo",
"deleteTemplate": "Delete Template", "deleteTemplate": "Izbriši predlogo",
"templateName": "Template Name", "templateName": "Ime predloge",
"templateNameHint": "e.g. Found Person", "templateNameHint": "npr. Najdena oseba",
"templateEmoji": "Emoji", "templateEmoji": "Emoji",
"emojiRequired": "Emoji je obvezen", "emojiRequired": "Emoji je obvezen",
"nameRequired": "Ime je obvezno", "nameRequired": "Ime je obvezno",
@@ -804,8 +808,8 @@
"templateDescriptionHint": "Add additional context...", "templateDescriptionHint": "Add additional context...",
"templateColor": "Color", "templateColor": "Color",
"previewFormat": "Preview (SAR Message Format)", "previewFormat": "Preview (SAR Message Format)",
"importFromClipboard": "Import", "importFromClipboard": "Uvozi",
"exportToClipboard": "Export", "exportToClipboard": "Izvozi",
"deleteTemplateConfirmation": "Delete template '{name}'?", "deleteTemplateConfirmation": "Delete template '{name}'?",
"templateAdded": "Template added", "templateAdded": "Template added",
"templateUpdated": "Template updated", "templateUpdated": "Template updated",
@@ -814,10 +818,10 @@
"templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}", "templatesExported": "{count, plural, =1{Exported 1 template to clipboard} other{Exported {count} templates to clipboard}}",
"importFailed": "Import failed: {error}", "importFailed": "Import failed: {error}",
"exportFailed": "Export failed: {error}", "exportFailed": "Export failed: {error}",
"resetToDefaults": "Reset to Defaults", "resetToDefaults": "Ponastavi na privzeto",
"resetToDefaultsConfirmation": "This will delete all custom templates and restore the 4 default templates. Continue?", "resetToDefaultsConfirmation": "To bo izbrisalo vse prilagojene predloge in obnovilo 4 privzete predloge. Nadaljevati?",
"reset": "Reset", "reset": "Ponastavi",
"resetComplete": "Templates reset to defaults", "resetComplete": "Predloge ponastavljene na privzeto",
"noTemplates": "No templates available", "noTemplates": "No templates available",
"tapAddToCreate": "Tap + to create your first template", "tapAddToCreate": "Tap + to create your first template",
"ok": "OK", "ok": "OK",
@@ -846,5 +850,55 @@
"noContactsOrRoomsAvailable": "Ni na voljo kontaktov ali sob", "noContactsOrRoomsAvailable": "Ni na voljo kontaktov ali sob",
"messagesWillBeSentToPublicChannel": "Sporočila bodo poslana na javni kanal", "messagesWillBeSentToPublicChannel": "Sporočila bodo poslana na javni kanal",
"newMessage": "Novo sporočilo", "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"
} }

View File

@@ -53,6 +53,7 @@ class Message {
final LatLng? sarGpsCoordinates; final LatLng? sarGpsCoordinates;
final String? sarNotes; // Optional message/notes for SAR marker final String? sarNotes; // Optional message/notes for SAR marker
final String? sarCustomEmoji; // Custom emoji for unknown SAR marker types final String? sarCustomEmoji; // Custom emoji for unknown SAR marker types
final int? sarColorIndex; // Color index (0-7) from standard palette
// Display metadata // Display metadata
final DateTime receivedAt; final DateTime receivedAt;
@@ -94,6 +95,7 @@ class Message {
this.sarGpsCoordinates, this.sarGpsCoordinates,
this.sarNotes, this.sarNotes,
this.sarCustomEmoji, this.sarCustomEmoji,
this.sarColorIndex,
required this.receivedAt, required this.receivedAt,
this.senderName, this.senderName,
this.deliveryStatus = MessageDeliveryStatus.received, this.deliveryStatus = MessageDeliveryStatus.received,
@@ -192,6 +194,7 @@ class Message {
senderName: senderName, senderName: senderName,
notes: sarNotes, // Use dedicated notes field instead of full text notes: sarNotes, // Use dedicated notes field instead of full text
customEmoji: sarCustomEmoji, // Preserve custom emoji for unknown types customEmoji: sarCustomEmoji, // Preserve custom emoji for unknown types
colorIndex: sarColorIndex, // Pass through color index
); );
} }
@@ -289,6 +292,7 @@ class Message {
LatLng? sarGpsCoordinates, LatLng? sarGpsCoordinates,
String? sarNotes, String? sarNotes,
String? sarCustomEmoji, String? sarCustomEmoji,
int? sarColorIndex,
DateTime? receivedAt, DateTime? receivedAt,
String? senderName, String? senderName,
MessageDeliveryStatus? deliveryStatus, MessageDeliveryStatus? deliveryStatus,
@@ -319,6 +323,7 @@ class Message {
sarGpsCoordinates: sarGpsCoordinates ?? this.sarGpsCoordinates, sarGpsCoordinates: sarGpsCoordinates ?? this.sarGpsCoordinates,
sarNotes: sarNotes ?? this.sarNotes, sarNotes: sarNotes ?? this.sarNotes,
sarCustomEmoji: sarCustomEmoji ?? this.sarCustomEmoji, sarCustomEmoji: sarCustomEmoji ?? this.sarCustomEmoji,
sarColorIndex: sarColorIndex ?? this.sarColorIndex,
receivedAt: receivedAt ?? this.receivedAt, receivedAt: receivedAt ?? this.receivedAt,
senderName: senderName ?? this.senderName, senderName: senderName ?? this.senderName,
deliveryStatus: deliveryStatus ?? this.deliveryStatus, deliveryStatus: deliveryStatus ?? this.deliveryStatus,

View File

@@ -77,6 +77,7 @@ class SarMarker {
final String? senderName; final String? senderName;
final String? notes; final String? notes;
final String? customEmoji; // For custom SAR markers not in predefined types final String? customEmoji; // For custom SAR markers not in predefined types
final int? colorIndex; // Color index (0-7) from standard palette
SarMarker({ SarMarker({
required this.id, required this.id,
@@ -87,6 +88,7 @@ class SarMarker {
this.senderName, this.senderName,
this.notes, this.notes,
this.customEmoji, this.customEmoji,
this.colorIndex,
}); });
/// Get sender public key as hex string (short) /// Get sender public key as hex string (short)
@@ -164,6 +166,7 @@ class SarMarker {
String? senderName, String? senderName,
String? notes, String? notes,
String? customEmoji, String? customEmoji,
int? colorIndex,
}) { }) {
return SarMarker( return SarMarker(
id: id ?? this.id, id: id ?? this.id,
@@ -174,6 +177,7 @@ class SarMarker {
senderName: senderName ?? this.senderName, senderName: senderName ?? this.senderName,
notes: notes ?? this.notes, notes: notes ?? this.notes,
customEmoji: customEmoji ?? this.customEmoji, customEmoji: customEmoji ?? this.customEmoji,
colorIndex: colorIndex ?? this.colorIndex,
); );
} }

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../l10n/app_localizations.dart';
/// SAR Template - Customizable template for SAR (Cursor on Target) messages /// SAR Template - Customizable template for SAR (Cursor on Target) messages
class SarTemplate { class SarTemplate {
@@ -9,6 +10,19 @@ class SarTemplate {
final String colorHex; final String colorHex;
final bool isDefault; 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<String> 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({ SarTemplate({
required this.id, required this.id,
required this.emoji, required this.emoji,
@@ -24,6 +38,77 @@ class SarTemplate {
return Color(int.parse('FF$hexCode', radix: 16)); 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 /// Create from JSON
factory SarTemplate.fromJson(Map<String, dynamic> json) { factory SarTemplate.fromJson(Map<String, dynamic> json) {
return SarTemplate( return SarTemplate(
@@ -90,37 +175,49 @@ class SarTemplate {
} }
/// Convert to SAR message format with placeholder coordinates /// 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() { String toSarMessage() {
final colorIndex = getColorIndex();
if (description.isNotEmpty) { 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) { static String _getColorForEmoji(String emoji) {
// Default emoji to color mapping // Default emoji to color mapping using standard palette
final colorMap = { final colorMap = {
'🧑': '#4CAF50', // Green - Person // Green (index 2) - Person, Safe, Nature
'👤': '#4CAF50', // Green - Person '🧑': colorPalette[2],
'🔥': '#F44336', // Red - Fire '👤': colorPalette[2],
'🏕️': '#FF9800', // Orange - Staging '': colorPalette[2],
'': '#FF9800', // Orange - Staging '🌲': colorPalette[2],
'📦': '#9C27B0', // Purple - Object
'🚁': '#2196F3', // Blue - Helicopter // Red (index 0) - Fire, Hazard, Medical, Emergency
'🚒': '#F44336', // Red - Fire truck '🔥': colorPalette[0],
'🚑': '#F44336', // Red - Ambulance '🚒': colorPalette[0],
'⚠️': '#FFC107', // Yellow - Warning '🚑': colorPalette[0],
'': '#F44336', // Red - Hazard '': colorPalette[0],
'': '#4CAF50', // Green - Safe '🏥': colorPalette[0],
'🏥': '#F44336', // Red - Medical
'💧': '#2196F3', // Blue - Water // Orange (index 4) - Staging, Assembly
'🌲': '#4CAF50', // Green - Forest '🏕️': colorPalette[4],
'⛰️': '#795548', // Brown - Mountain '': 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 /// Copy with modifications
@@ -156,7 +253,16 @@ class SarTemplate {
@override @override
int get hashCode => id.hashCode; 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<SarTemplate> get defaults { static List<SarTemplate> get defaults {
return [ return [
SarTemplate( SarTemplate(
@@ -164,7 +270,7 @@ class SarTemplate {
emoji: '🧑', emoji: '🧑',
name: 'Found Person', name: 'Found Person',
description: '', description: '',
colorHex: '#4CAF50', colorHex: colorPalette[2], // Green
isDefault: true, isDefault: true,
), ),
SarTemplate( SarTemplate(
@@ -172,7 +278,7 @@ class SarTemplate {
emoji: '🔥', emoji: '🔥',
name: 'Fire', name: 'Fire',
description: '', description: '',
colorHex: '#F44336', colorHex: colorPalette[0], // Red
isDefault: true, isDefault: true,
), ),
SarTemplate( SarTemplate(
@@ -180,7 +286,7 @@ class SarTemplate {
emoji: '🏕️', emoji: '🏕️',
name: 'Staging Area', name: 'Staging Area',
description: '', description: '',
colorHex: '#FF9800', colorHex: colorPalette[4], // Orange
isDefault: true, isDefault: true,
), ),
SarTemplate( SarTemplate(
@@ -188,7 +294,7 @@ class SarTemplate {
emoji: '📦', emoji: '📦',
name: 'Object', name: 'Object',
description: '', description: '',
colorHex: '#9C27B0', colorHex: colorPalette[5], // Purple
isDefault: true, isDefault: true,
), ),
]; ];

View File

@@ -878,8 +878,8 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
builder: (context) => SarUpdateSheet( builder: (context) => SarUpdateSheet(
prePopulatedPosition: position, prePopulatedPosition: position,
allowLocationUpdate: false, // Don't allow changing to current location allowLocationUpdate: false, // Don't allow changing to current location
onSend: (emoji, name, position, roomPublicKey, sendToChannel) async { onSend: (emoji, name, position, roomPublicKey, sendToChannel, colorIndex) async {
await _sendSarMessage(emoji, name, position, roomPublicKey, sendToChannel); await _sendSarMessage(emoji, name, position, roomPublicKey, sendToChannel, colorIndex);
}, },
), ),
); );
@@ -891,6 +891,7 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
Position position, Position position,
Uint8List? roomPublicKey, Uint8List? roomPublicKey,
bool sendToChannel, bool sendToChannel,
int colorIndex,
) async { ) async {
final connectionProvider = context.read<ConnectionProvider>(); final connectionProvider = context.read<ConnectionProvider>();
final messagesProvider = context.read<MessagesProvider>(); final messagesProvider = context.read<MessagesProvider>();
@@ -918,9 +919,9 @@ class _MapTabState extends State<MapTab> with AutomaticKeepAliveClientMixin {
} }
try { try {
// Format: S:<emoji>:<latitude>,<longitude>:<name> // New format: S:<emoji>:<colorIndex>:<latitude>,<longitude>:<name>
// Round coordinates to 5 decimal places (~1m accuracy) since most GPS is only that accurate // 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) { if (sendToChannel) {
// Create message ID // Create message ID

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import '../providers/messages_provider.dart'; import '../providers/messages_provider.dart';
@@ -64,8 +65,9 @@ class _MessagesTabState extends State<MessagesTab> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
// Check for navigation request whenever dependencies change // Reload saved destination and check for navigation request whenever dependencies change
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_loadSavedDestination();
_checkForNavigationRequest(); _checkForNavigationRequest();
}); });
} }
@@ -387,13 +389,14 @@ class _MessagesTabState extends State<MessagesTab> {
isScrollControlled: true, isScrollControlled: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
builder: (context) => SarUpdateSheet( builder: (context) => SarUpdateSheet(
onSend: (emoji, name, position, roomPublicKey, sendToChannel) async { onSend: (emoji, name, position, roomPublicKey, sendToChannel, colorIndex) async {
await _sendSarMessage( await _sendSarMessage(
emoji, emoji,
name, name,
position, position,
roomPublicKey, roomPublicKey,
sendToChannel, sendToChannel,
colorIndex,
); );
}, },
), ),
@@ -406,6 +409,7 @@ class _MessagesTabState extends State<MessagesTab> {
Position position, Position position,
Uint8List? roomPublicKey, Uint8List? roomPublicKey,
bool sendToChannel, bool sendToChannel,
int colorIndex,
) async { ) async {
final connectionProvider = context.read<ConnectionProvider>(); final connectionProvider = context.read<ConnectionProvider>();
final messagesProvider = context.read<MessagesProvider>(); final messagesProvider = context.read<MessagesProvider>();
@@ -423,10 +427,10 @@ class _MessagesTabState extends State<MessagesTab> {
} }
try { try {
// Format: S:<emoji>:<latitude>,<longitude>:<name> // New format: S:<emoji>:<colorIndex>:<latitude>,<longitude>:<name>
// Round coordinates to 5 decimal places (~1m accuracy) since most GPS is only that accurate // Round coordinates to 5 decimal places (~1m accuracy) since most GPS is only that accurate
final sarMessage = 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) { if (sendToChannel) {
// Create message ID // Create message ID
@@ -551,9 +555,51 @@ class _MessagesTabState extends State<MessagesTab> {
} }
List<Message> _getFilteredMessages(MessagesProvider messagesProvider) { List<Message> _getFilteredMessages(MessagesProvider messagesProvider) {
// Show ALL messages regardless of recipient selection // Get all recent messages
// The recipient selector only controls where NEW messages are sent final allMessages = messagesProvider.getRecentMessages(count: 100);
return 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 @override
@@ -831,6 +877,8 @@ class _MessageBubble extends StatelessWidget {
contact: roomContact, // Include contact for path status logging contact: roomContact, // Include contact for path status logging
); );
if (!context.mounted) return;
if (!sentSuccessfully) { if (!sentSuccessfully) {
messagesProvider.markMessageFailed(retryMessageId); messagesProvider.markMessageFailed(retryMessageId);
ToastLogger.error(context, 'Failed to resend message'); ToastLogger.error(context, 'Failed to resend message');
@@ -845,9 +893,12 @@ class _MessageBubble extends StatelessWidget {
messageId: retryMessageId, messageId: retryMessageId,
); );
if (!context.mounted) return;
ToastLogger.info(context, 'Retrying message...'); ToastLogger.info(context, 'Retrying message...');
} }
} catch (e) { } catch (e) {
if (!context.mounted) return;
ToastLogger.error(context, 'Retry failed: $e'); 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 // Delete message option
ListTile( ListTile(
leading: const Icon(Icons.delete, color: Colors.red), 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isSarMarker = message.isSarMarker; final isSarMarker = message.isSarMarker;

View File

@@ -81,7 +81,7 @@ class _SarTemplateManagementScreenState extends State<SarTemplateManagementScree
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text(AppLocalizations.of(context)!.deleteTemplate), title: Text(AppLocalizations.of(context)!.deleteTemplate),
content: Text( content: Text(
AppLocalizations.of(context)!.deleteTemplateConfirmation(template.name), AppLocalizations.of(context)!.deleteTemplateConfirmation(template.getLocalizedName(context)),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -351,7 +351,7 @@ class _TemplateListItem extends StatelessWidget {
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text(AppLocalizations.of(context)!.deleteTemplate), title: Text(AppLocalizations.of(context)!.deleteTemplate),
content: Text( content: Text(
AppLocalizations.of(context)!.deleteTemplateConfirmation(template.name), AppLocalizations.of(context)!.deleteTemplateConfirmation(template.getLocalizedName(context)),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -394,7 +394,7 @@ class _TemplateListItem extends StatelessWidget {
title: Row( title: Row(
children: [ children: [
Text( Text(
template.name, template.getLocalizedName(context),
style: theme.textTheme.titleMedium?.copyWith( style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),

View File

@@ -178,15 +178,20 @@ class _SettingsScreenState extends State<SettingsScreen> {
if (!mounted) return; if (!mounted) return;
// Get localization
final l10n = AppLocalizations.of(context)!;
// Generate sample data // Generate sample data
final contacts = SampleDataGenerator.generateContacts( final contacts = SampleDataGenerator.generateContacts(
centerLocation: centerLocation, centerLocation: centerLocation,
l10n: l10n,
teamMemberCount: 5, teamMemberCount: 5,
channelCount: 2, channelCount: 2,
); );
final sarMessages = SampleDataGenerator.generateSarMarkerMessages( final sarMessages = SampleDataGenerator.generateSarMarkerMessages(
centerLocation: centerLocation, centerLocation: centerLocation,
l10n: l10n,
foundPersonCount: 2, foundPersonCount: 2,
fireCount: 1, fireCount: 1,
stagingCount: 1, stagingCount: 1,
@@ -195,6 +200,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
final channelMessages = SampleDataGenerator.generateChannelMessages( final channelMessages = SampleDataGenerator.generateChannelMessages(
centerLocation: centerLocation, centerLocation: centerLocation,
l10n: l10n,
generalChannelMessages: 8, generalChannelMessages: 8,
emergencyChannelMessages: 5, emergencyChannelMessages: 5,
); );

View File

@@ -5,6 +5,7 @@ import '../models/contact.dart';
import '../models/contact_telemetry.dart'; import '../models/contact_telemetry.dart';
import '../models/message.dart'; import '../models/message.dart';
import '../models/sar_marker.dart'; import '../models/sar_marker.dart';
import '../l10n/app_localizations.dart';
/// Generates sample data for testing/demo purposes /// Generates sample data for testing/demo purposes
class SampleDataGenerator { class SampleDataGenerator {
@@ -13,6 +14,7 @@ class SampleDataGenerator {
/// Generate sample contacts around a center location /// Generate sample contacts around a center location
static List<Contact> generateContacts({ static List<Contact> generateContacts({
required LatLng centerLocation, required LatLng centerLocation,
required AppLocalizations l10n,
int teamMemberCount = 5, int teamMemberCount = 5,
int channelCount = 2, int channelCount = 2,
}) { }) {
@@ -20,21 +22,21 @@ class SampleDataGenerator {
final now = DateTime.now(); final now = DateTime.now();
final teamNames = [ final teamNames = [
'👮Police Lead', '👮${l10n.samplePoliceLead}',
'🚁Drone Operator', '🚁${l10n.sampleDroneOperator}',
'🧑🏻🚒Firefighter Alpha', '🧑🏻‍🚒${l10n.sampleFirefighterAlpha}',
'🧑Medic Charlie', '🧑‍⚕️${l10n.sampleMedicCharlie}',
'📡Command Delta', '📡${l10n.sampleCommandDelta}',
'🚒Fire Engine', '🚒${l10n.sampleFireEngine}',
'👨Air Support', '👨‍✈️${l10n.sampleAirSupport}',
'🧑💼Base Coordinator', '🧑‍💼${l10n.sampleBaseCoordinator}',
]; ];
final channelNames = [ final channelNames = [
'General', l10n.general,
'Emergency', l10n.channelEmergency,
'Coordination', l10n.channelCoordination,
'Updates', l10n.channelUpdates,
]; ];
// Generate team members (chat contacts) // Generate team members (chat contacts)
@@ -114,6 +116,7 @@ class SampleDataGenerator {
/// Generate sample SAR markers around a center location /// Generate sample SAR markers around a center location
static List<Message> generateSarMarkerMessages({ static List<Message> generateSarMarkerMessages({
required LatLng centerLocation, required LatLng centerLocation,
required AppLocalizations l10n,
int foundPersonCount = 2, int foundPersonCount = 2,
int fireCount = 1, int fireCount = 1,
int stagingCount = 1, int stagingCount = 1,
@@ -147,7 +150,7 @@ class SampleDataGenerator {
isSarMarker: true, isSarMarker: true,
sarMarkerType: SarMarkerType.foundPerson, sarMarkerType: SarMarkerType.foundPerson,
sarGpsCoordinates: LatLng(lat, lon), sarGpsCoordinates: LatLng(lat, lon),
senderName: 'Sample Team Member', senderName: l10n.sampleTeamMember,
)); ));
messageId++; messageId++;
} }
@@ -176,7 +179,7 @@ class SampleDataGenerator {
isSarMarker: true, isSarMarker: true,
sarMarkerType: SarMarkerType.fire, sarMarkerType: SarMarkerType.fire,
sarGpsCoordinates: LatLng(lat, lon), sarGpsCoordinates: LatLng(lat, lon),
senderName: 'Sample Scout', senderName: l10n.sampleScout,
)); ));
messageId++; messageId++;
} }
@@ -205,7 +208,7 @@ class SampleDataGenerator {
isSarMarker: true, isSarMarker: true,
sarMarkerType: SarMarkerType.stagingArea, sarMarkerType: SarMarkerType.stagingArea,
sarGpsCoordinates: LatLng(lat, lon), sarGpsCoordinates: LatLng(lat, lon),
senderName: 'Sample Base', senderName: l10n.sampleBase,
)); ));
messageId++; messageId++;
} }
@@ -223,10 +226,10 @@ class SampleDataGenerator {
final timestamp = now.subtract(Duration(minutes: 40 + i * 5)); final timestamp = now.subtract(Duration(minutes: 40 + i * 5));
final notes = [ final notes = [
' Backpack found - blue color', l10n.sampleObjectBackpack,
' Vehicle abandoned - check for owner', l10n.sampleObjectVehicle,
' Camping equipment discovered', l10n.sampleObjectCamping,
' Trail marker found off-path', l10n.sampleObjectTrailMarker,
]; ];
messages.add(Message( messages.add(Message(
@@ -241,7 +244,7 @@ class SampleDataGenerator {
isSarMarker: true, isSarMarker: true,
sarMarkerType: SarMarkerType.object, sarMarkerType: SarMarkerType.object,
sarGpsCoordinates: LatLng(lat, lon), sarGpsCoordinates: LatLng(lat, lon),
senderName: 'Sample Searcher', senderName: l10n.sampleSearcher,
)); ));
messageId++; messageId++;
} }
@@ -252,6 +255,7 @@ class SampleDataGenerator {
/// Generate sample channel messages for public channels /// Generate sample channel messages for public channels
static List<Message> generateChannelMessages({ static List<Message> generateChannelMessages({
LatLng? centerLocation, LatLng? centerLocation,
required AppLocalizations l10n,
int generalChannelMessages = 8, int generalChannelMessages = 8,
int emergencyChannelMessages = 5, int emergencyChannelMessages = 5,
}) { }) {
@@ -263,44 +267,44 @@ class SampleDataGenerator {
// Sample messages for General channel (index 0) // Sample messages for General channel (index 0)
final generalMessages = [ final generalMessages = [
'All teams check in', l10n.sampleMsgAllTeamsCheckIn,
'Weather update: Clear skies, temp 18°C', l10n.sampleMsgWeatherUpdate,
'Base camp established at staging area', l10n.sampleMsgBaseCamp,
'Team Alpha moving to sector 2', l10n.sampleMsgTeamAlpha,
'Radio check - all stations respond', l10n.sampleMsgRadioCheck,
'Water supply available at checkpoint 3', l10n.sampleMsgWaterSupply,
'Team Bravo reporting: sector 1 clear', l10n.sampleMsgTeamBravo,
'ETA to rally point: 15 minutes', l10n.sampleMsgEtaRallyPoint,
'Supply drop confirmed for 14:00', l10n.sampleMsgSupplyDrop,
'Drone survey completed - no findings', l10n.sampleMsgDroneSurvey,
'Team Charlie requesting backup', l10n.sampleMsgTeamCharlie,
'All units: maintain radio discipline', l10n.sampleMsgRadioDiscipline,
]; ];
// Sample messages for Emergency channel (index 1) // Sample messages for Emergency channel (index 1)
// Mix regular messages and SAR markers // Mix regular messages and SAR markers
final emergencyMessages = [ final emergencyMessages = [
'URGENT: Medical assistance needed at sector 4', l10n.sampleMsgUrgentMedical,
'S:🧑:${center.latitude.toStringAsFixed(5)},${(center.longitude + 0.005).toStringAsFixed(5)} Adult male, conscious', 'S:🧑:${center.latitude.toStringAsFixed(5)},${(center.longitude + 0.005).toStringAsFixed(5)}${l10n.sampleMsgAdultMale}',
'Fire spotted - coordinates incoming', l10n.sampleMsgFireSpotted,
'S:🔥:${(center.latitude + 0.008).toStringAsFixed(5)},${(center.longitude + 0.003).toStringAsFixed(5)} Spreading rapidly!', 'S:🔥:${(center.latitude + 0.008).toStringAsFixed(5)},${(center.longitude + 0.003).toStringAsFixed(5)}${l10n.sampleMsgSpreadingRapidly}',
'PRIORITY: Need helicopter support', l10n.sampleMsgPriorityHelicopter,
'Medical team en route to your location', l10n.sampleMsgMedicalTeamEnRoute,
'Evac helicopter ETA 10 minutes', l10n.sampleMsgEvacHelicopter,
'Emergency resolved - all clear', l10n.sampleMsgEmergencyResolved,
'S:🏕️:${(center.latitude - 0.002).toStringAsFixed(5)},${(center.longitude - 0.004).toStringAsFixed(5)} Emergency staging area', 'S:🏕️:${(center.latitude - 0.002).toStringAsFixed(5)},${(center.longitude - 0.004).toStringAsFixed(5)}${l10n.sampleMsgEmergencyStagingArea}',
'Emergency services notified and responding', l10n.sampleMsgEmergencyServices,
]; ];
final teamNames = [ final teamNames = [
'Alpha Team Lead', l10n.sampleAlphaTeamLead,
'Bravo Scout', l10n.sampleBravoScout,
'Charlie Medic', l10n.sampleCharlieMedic,
'Delta Navigator', l10n.sampleDeltaNavigator,
'Echo Support', l10n.sampleEchoSupport,
'Base Command', l10n.sampleBaseCommand,
'Field Coordinator', l10n.sampleFieldCoordinator,
'Medical Team', l10n.sampleMedicalTeam,
]; ];
// Generate General channel messages // Generate General channel messages

View File

@@ -3,16 +3,23 @@ import '../models/sar_marker.dart';
import '../models/message.dart'; import '../models/message.dart';
/// Parser for SAR (Search & Rescue) special messages /// Parser for SAR (Search & Rescue) special messages
/// Format: S:<emoji>:<latitude>,<longitude>:<optional_message> /// Old format: S:<emoji>:<latitude>,<longitude>:<optional_message>
/// New format: S:<emoji>:<colorIndex>:<latitude>,<longitude>:<optional_message>
/// Examples: /// Examples:
/// S:🧑:37.7749,-122.4194 /// S:🧑:37.7749,-122.4194 (old format)
/// S:🔥:40.7128,-74.0060:Large wildfire spreading /// S:🧑:2:37.7749,-122.4194 (new format with green color)
/// S:🏕️:34.0522,-118.2437:Base camp established /// S:🔥:0:40.7128,-74.0060:Large wildfire spreading (new format with red color)
class SarMessageParser { class SarMessageParser {
// Updated regex to capture optional message after coordinates // Regex for new format with color index: S:emoji:colorIndex:lat,lon:notes
// Captures: emoji (one or more non-colon chars), latitude, longitude, optional message // Captures: emoji, colorIndex (single digit), latitude, longitude, optional message
// Note: Emojis are multi-byte characters, so we use [^:]+ instead of . static final RegExp _sarPatternNew = RegExp(
static final RegExp _sarPattern = 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*):?(.*)', r'^S:([^:]+):(-?\d+\.?\d*),(-?\d+\.?\d*):?(.*)',
multiLine: false, multiLine: false,
); );
@@ -21,30 +28,61 @@ class SarMessageParser {
static bool isSarMessage(String text) { static bool isSarMessage(String text) {
// Extract just the first line for matching // Extract just the first line for matching
final firstLine = text.trim().split('\n').first; 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 /// Parse a SAR message and extract marker information
/// Returns null if the message is not a valid SAR message /// 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) { static SarMarkerInfo? parse(String text) {
final trimmed = text.trim(); final trimmed = text.trim();
if (!trimmed.startsWith('S:')) return null; if (!trimmed.startsWith('S:')) return null;
// Extract first line (actual SAR marker) // Extract first line (actual SAR marker)
final firstLine = trimmed.split('\n').first; 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 { try {
final emoji = match.group(1)!; String emoji;
final latitude = double.parse(match.group(2)!); double latitude;
final longitude = double.parse(match.group(3)!); double longitude;
final inlineMessage = match.group(4)?.trim(); // Optional message after colon 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 // Validate coordinates
if (latitude < -90 || latitude > 90) return null; if (latitude < -90 || latitude > 90) return null;
if (longitude < -180 || longitude > 180) 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 markerType = SarMarkerType.fromEmoji(emoji);
final location = LatLng(latitude, longitude); final location = LatLng(latitude, longitude);
@@ -65,6 +103,7 @@ class SarMessageParser {
location: location, location: location,
emoji: emoji, emoji: emoji,
notes: notes, notes: notes,
colorIndex: colorIndex,
); );
} catch (e) { } catch (e) {
return null; return null;
@@ -84,16 +123,20 @@ class SarMessageParser {
sarCustomEmoji: sarInfo.type == SarMarkerType.unknown sarCustomEmoji: sarInfo.type == SarMarkerType.unknown
? sarInfo.emoji // Preserve custom emoji for unknown types ? sarInfo.emoji // Preserve custom emoji for unknown types
: null, : 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({ static String createSarMessage({
required SarMarkerType type, required SarMarkerType type,
required LatLng location, required LatLng location,
String? notes, 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) { if (notes != null && notes.isNotEmpty) {
// Use colon-separated format for inline message // Use colon-separated format for inline message
return '$text:$notes'; return '$text:$notes';
@@ -166,16 +209,18 @@ class SarMarkerInfo {
final LatLng location; final LatLng location;
final String emoji; final String emoji;
final String? notes; final String? notes;
final int? colorIndex; // Color index from standard palette (0-7), null for backward compatibility
SarMarkerInfo({ SarMarkerInfo({
required this.type, required this.type,
required this.location, required this.location,
required this.emoji, required this.emoji,
this.notes, this.notes,
this.colorIndex,
}); });
@override @override
String toString() { String toString() {
return 'SarMarkerInfo(type: ${type.displayName}, location: $location, notes: $notes)'; return 'SarMarkerInfo(type: ${type.displayName}, location: $location, colorIndex: $colorIndex, notes: $notes)';
} }
} }

View File

@@ -9,6 +9,7 @@ import '../../models/message.dart';
import '../../providers/connection_provider.dart'; import '../../providers/connection_provider.dart';
import '../../providers/messages_provider.dart'; import '../../providers/messages_provider.dart';
import '../../providers/app_provider.dart'; import '../../providers/app_provider.dart';
import '../../services/message_destination_preferences.dart';
import '../../utils/toast_logger.dart'; import '../../utils/toast_logger.dart';
import '../../l10n/app_localizations.dart'; import '../../l10n/app_localizations.dart';
@@ -159,6 +160,15 @@ class _DirectMessageSheetState extends State<DirectMessageSheet> {
messagesProvider.markMessageFailed(messageId); 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(); _textController.clear();
_focusNode.unfocus(); _focusNode.unfocus();

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import '../models/contact.dart'; import '../models/contact.dart';
import '../models/sar_marker.dart'; import '../models/sar_marker.dart';
import '../models/sar_template.dart';
import '../l10n/app_localizations.dart'; import '../l10n/app_localizations.dart';
class MapMarkers { class MapMarkers {
@@ -129,7 +130,7 @@ class MapMarkers {
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getSarMarkerColor(marker.type), color: _getSarMarkerColor(marker),
borderRadius: BorderRadius.circular(3), borderRadius: BorderRadius.circular(3),
), ),
child: Text( child: Text(
@@ -145,7 +146,7 @@ class MapMarkers {
// Marker emoji/icon // Marker emoji/icon
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: _getSarMarkerColor(marker.type), color: _getSarMarkerColor(marker),
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2), border: Border.all(color: Colors.white, width: 2),
boxShadow: [ boxShadow: [
@@ -302,8 +303,16 @@ class MapMarkers {
return Colors.red; // Stale return Colors.red; // Stale
} }
static Color _getSarMarkerColor(SarMarkerType type) { static Color _getSarMarkerColor(SarMarker marker) {
switch (type) { // 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: case SarMarkerType.foundPerson:
return Colors.green; return Colors.green;
case SarMarkerType.fire: case SarMarkerType.fire:

View File

@@ -18,6 +18,7 @@ class SarUpdateSheet extends StatefulWidget {
Position, Position,
Uint8List?, Uint8List?,
bool, bool,
int colorIndex,
) )
onSend; onSend;
final Position? prePopulatedPosition; final Position? prePopulatedPosition;
@@ -784,7 +785,7 @@ class _SarUpdateSheetState extends State<SarUpdateSheet> {
displayText = _selectedTemplate!.name; displayText = _selectedTemplate!.name;
} }
// Send SAR marker with emoji and display text // Send SAR marker with emoji, display text, and color index
await widget.onSend( await widget.onSend(
_selectedTemplate!.emoji, _selectedTemplate!.emoji,
displayText, displayText,
@@ -793,6 +794,7 @@ class _SarUpdateSheetState extends State<SarUpdateSheet> {
? null ? null
: _selectedContact!.publicKey, : _selectedContact!.publicKey,
_selectedContact!.isChannel, _selectedContact!.isChannel,
_selectedTemplate!.getColorIndex(), // Include color index
); );
if (context.mounted) { if (context.mounted) {
Navigator.pop(context); Navigator.pop(context);
@@ -869,7 +871,7 @@ class TemplateChip extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
template.name, template.getLocalizedName(context),
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,