From e43b386029c8564a7099c9dfc78b37e9a92c5b9f Mon Sep 17 00:00:00 2001 From: Janez T Date: Sun, 1 Mar 2026 11:20:14 +0100 Subject: [PATCH] Build latest Android apk --- lib/l10n/app_de.arb | 53 ++++++- lib/l10n/app_el.arb | 53 ++++++- lib/l10n/app_en.arb | 78 ++++++++- lib/l10n/app_es.arb | 53 ++++++- lib/l10n/app_fr.arb | 53 ++++++- lib/l10n/app_hr.arb | 53 ++++++- lib/l10n/app_it.arb | 53 ++++++- lib/l10n/app_localizations.dart | 150 ++++++++++++++++++ lib/l10n/app_localizations_de.dart | 76 +++++++++ lib/l10n/app_localizations_el.dart | 76 +++++++++ lib/l10n/app_localizations_en.dart | 76 +++++++++ lib/l10n/app_localizations_es.dart | 76 +++++++++ lib/l10n/app_localizations_fr.dart | 76 +++++++++ lib/l10n/app_localizations_hr.dart | 76 +++++++++ lib/l10n/app_localizations_it.dart | 76 +++++++++ lib/l10n/app_localizations_sl.dart | 76 +++++++++ lib/l10n/app_sl.arb | 53 ++++++- lib/screens/messages_tab.dart | 2 +- lib/services/voice_codec_service.dart | 6 +- lib/widgets/messages/message_bubble.dart | 70 ++++---- .../messages/voice_message_bubble.dart | 7 +- 21 files changed, 1244 insertions(+), 48 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index d8097f2..a9b1260 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -2832,4 +2832,55 @@ "directMessagesInfo": "Direktnachrichten mit Bestätigungen. An {count} Teammitglieder gesendet.", "sarMarkerSentToContacts": "SAR-Marker an {count} Kontakte gesendet", "noContactsAvailable": "Keine Team-Kontakte verfügbar" -} +, + + "reply": "Antworten", + + "technicalDetails": "Technische Details", + + "messageTechnicalDetails": "Technische Nachrichtendetails", + + "linkQuality": "Verbindungsqualität", + + "delivery": "Zustellung", + + "status": "Status", + + "expectedAckTag": "Erwartetes ACK-Tag", + + "roundTrip": "Roundtrip", + + "retryAttempt": "Wiederholungsversuch", + + "floodFallback": "Flood-Fallback", + + "identity": "Identität", + + "messageId": "Nachrichten-ID", + + "sender": "Absender", + + "senderKey": "Absenderschlüssel", + + "recipient": "Empfänger", + + "recipientKey": "Empfängerschlüssel", + + "voice": "Sprachnachricht", + + "voiceId": "Sprach-ID", + + "envelope": "Umschlag", + + "sessionProgress": "Sitzungsfortschritt", + + "complete": "Vollständig", + + "rawDump": "Rohdaten", + + "cannotRetryMissingRecipient": "Wiederholung nicht möglich: Empfängerinformationen fehlen", + + "voiceUnavailable": "Sprachnachricht momentan nicht verfügbar", + + "requestingVoice": "Sprachnachricht wird angefordert" +} \ No newline at end of file diff --git a/lib/l10n/app_el.arb b/lib/l10n/app_el.arb index a85f587..3a59ccc 100644 --- a/lib/l10n/app_el.arb +++ b/lib/l10n/app_el.arb @@ -3790,4 +3790,55 @@ "@noContactsAvailable": { "description": "Message when there are no chat contacts to send to" } -} +, + + "reply": "Απάντηση", + + "technicalDetails": "Τεχνικές λεπτομέρειες", + + "messageTechnicalDetails": "Τεχνικές λεπτομέρειες μηνύματος", + + "linkQuality": "Ποιότητα σύνδεσης", + + "delivery": "Παράδοση", + + "status": "Κατάσταση", + + "expectedAckTag": "Αναμενόμενη ετικέτα ACK", + + "roundTrip": "Χρόνος μετ' επιστροφής", + + "retryAttempt": "Απόπειρα επανάληψης", + + "floodFallback": "Εφεδρική πλημμύρα", + + "identity": "Ταυτότητα", + + "messageId": "Αναγνωριστικό μηνύματος", + + "sender": "Αποστολέας", + + "senderKey": "Κλειδί αποστολέα", + + "recipient": "Παραλήπτης", + + "recipientKey": "Κλειδί παραλήπτη", + + "voice": "Φωνή", + + "voiceId": "Αναγνωριστικό φωνής", + + "envelope": "Φάκελος", + + "sessionProgress": "Πρόοδος συνεδρίας", + + "complete": "Ολοκληρώθηκε", + + "rawDump": "Ακατέργαστα δεδομένα", + + "cannotRetryMissingRecipient": "Δεν είναι δυνατή η επανάληψη: λείπουν πληροφορίες παραλήπτη", + + "voiceUnavailable": "Η φωνή δεν είναι διαθέσιμη αυτή τη στιγμή", + + "requestingVoice": "Αίτηση φωνής" +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 51e1914..088edbf 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -3790,4 +3790,80 @@ "@noContactsAvailable": { "description": "Message when there are no chat contacts to send to" } -} +, + + "reply": "Reply", + "@reply": {}, + + "technicalDetails": "Technical details", + "@technicalDetails": {}, + + "messageTechnicalDetails": "Message technical details", + "@messageTechnicalDetails": {}, + + "linkQuality": "Link quality", + "@linkQuality": {}, + + "delivery": "Delivery", + "@delivery": {}, + + "status": "Status", + "@status": {}, + + "expectedAckTag": "Expected ACK tag", + "@expectedAckTag": {}, + + "roundTrip": "Round-trip", + "@roundTrip": {}, + + "retryAttempt": "Retry attempt", + "@retryAttempt": {}, + + "floodFallback": "Flood fallback", + "@floodFallback": {}, + + "identity": "Identity", + "@identity": {}, + + "messageId": "Message ID", + "@messageId": {}, + + "sender": "Sender", + "@sender": {}, + + "senderKey": "Sender key", + "@senderKey": {}, + + "recipient": "Recipient", + "@recipient": {}, + + "recipientKey": "Recipient key", + "@recipientKey": {}, + + "voice": "Voice", + "@voice": {}, + + "voiceId": "Voice ID", + "@voiceId": {}, + + "envelope": "Envelope", + "@envelope": {}, + + "sessionProgress": "Session progress", + "@sessionProgress": {}, + + "complete": "Complete", + "@complete": {}, + + "rawDump": "Raw dump", + "@rawDump": {}, + + "cannotRetryMissingRecipient": "Cannot retry: recipient information missing", + "@cannotRetryMissingRecipient": {}, + + "voiceUnavailable": "Voice unavailable right now", + "@voiceUnavailable": {}, + + "requestingVoice": "Requesting voice", + "@requestingVoice": {} +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index f6ca905..035e3a8 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2827,4 +2827,55 @@ "directMessagesInfo": "Mensajes directos con confirmaciones. Enviado a {count} miembros del equipo.", "sarMarkerSentToContacts": "Marcador SAR enviado a {count} contactos", "noContactsAvailable": "No hay contactos del equipo disponibles" -} +, + + "reply": "Responder", + + "technicalDetails": "Detalles técnicos", + + "messageTechnicalDetails": "Detalles técnicos del mensaje", + + "linkQuality": "Calidad del enlace", + + "delivery": "Entrega", + + "status": "Estado", + + "expectedAckTag": "Etiqueta ACK esperada", + + "roundTrip": "Ida y vuelta", + + "retryAttempt": "Intento de reenvío", + + "floodFallback": "Reserva de inundación", + + "identity": "Identidad", + + "messageId": "ID de mensaje", + + "sender": "Remitente", + + "senderKey": "Clave del remitente", + + "recipient": "Destinatario", + + "recipientKey": "Clave del destinatario", + + "voice": "Voz", + + "voiceId": "ID de voz", + + "envelope": "Envolvente", + + "sessionProgress": "Progreso de sesión", + + "complete": "Completo", + + "rawDump": "Volcado sin procesar", + + "cannotRetryMissingRecipient": "No se puede reintentar: falta información del destinatario", + + "voiceUnavailable": "Voz no disponible en este momento", + + "requestingVoice": "Solicitando voz" +} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 7f1932b..449b384 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -2835,4 +2835,55 @@ "directMessagesInfo": "Messages directs avec confirmations. Envoyé à {count} membres de l'équipe.", "sarMarkerSentToContacts": "Marqueur SAR envoyé à {count} contacts", "noContactsAvailable": "Aucun contact d'équipe disponible" -} +, + + "reply": "Répondre", + + "technicalDetails": "Détails techniques", + + "messageTechnicalDetails": "Détails techniques du message", + + "linkQuality": "Qualité du lien", + + "delivery": "Livraison", + + "status": "Statut", + + "expectedAckTag": "Balise ACK attendue", + + "roundTrip": "Aller-retour", + + "retryAttempt": "Tentative de renvoi", + + "floodFallback": "Repli inondation", + + "identity": "Identité", + + "messageId": "ID du message", + + "sender": "Expéditeur", + + "senderKey": "Clé de l'expéditeur", + + "recipient": "Destinataire", + + "recipientKey": "Clé du destinataire", + + "voice": "Voix", + + "voiceId": "ID vocal", + + "envelope": "Enveloppe", + + "sessionProgress": "Progression de session", + + "complete": "Complet", + + "rawDump": "Vidage brut", + + "cannotRetryMissingRecipient": "Impossible de réessayer : informations du destinataire manquantes", + + "voiceUnavailable": "Voix indisponible pour le moment", + + "requestingVoice": "Demande de voix" +} \ No newline at end of file diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index 00eeccd..3bd66a0 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -1103,4 +1103,55 @@ "directMessagesInfo": "Izravne poruke s potvrdom. Poslano {count} članovima tima.", "sarMarkerSentToContacts": "SAR oznaka poslana {count} kontaktima", "noContactsAvailable": "Nema dostupnih kontakata tima" -} +, + + "reply": "Odgovori", + + "technicalDetails": "Tehnički detalji", + + "messageTechnicalDetails": "Tehnički detalji poruke", + + "linkQuality": "Kvaliteta veze", + + "delivery": "Dostava", + + "status": "Status", + + "expectedAckTag": "Očekivana ACK oznaka", + + "roundTrip": "Povratno putovanje", + + "retryAttempt": "Pokušaj ponovnog slanja", + + "floodFallback": "Flood rezerva", + + "identity": "Identitet", + + "messageId": "ID poruke", + + "sender": "Pošiljatelj", + + "senderKey": "Ključ pošiljatelja", + + "recipient": "Primatelj", + + "recipientKey": "Ključ primatelja", + + "voice": "Glas", + + "voiceId": "ID glasa", + + "envelope": "Omotnica", + + "sessionProgress": "Napredak sesije", + + "complete": "Dovršeno", + + "rawDump": "Sirovi ispis", + + "cannotRetryMissingRecipient": "Nije moguće ponoviti: nedostaju informacije o primatelju", + + "voiceUnavailable": "Glas trenutno nije dostupan", + + "requestingVoice": "Zahtjev za glasom" +} \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index daf172a..7e61c4d 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -2835,4 +2835,55 @@ "directMessagesInfo": "Messaggi diretti con conferme. Inviato a {count} membri del team.", "sarMarkerSentToContacts": "Marcatore SAR inviato a {count} contatti", "noContactsAvailable": "Nessun contatto del team disponibile" -} +, + + "reply": "Rispondi", + + "technicalDetails": "Dettagli tecnici", + + "messageTechnicalDetails": "Dettagli tecnici del messaggio", + + "linkQuality": "Qualità del collegamento", + + "delivery": "Consegna", + + "status": "Stato", + + "expectedAckTag": "Tag ACK atteso", + + "roundTrip": "Andata e ritorno", + + "retryAttempt": "Tentativo di nuovo invio", + + "floodFallback": "Fallback inondazione", + + "identity": "Identità", + + "messageId": "ID messaggio", + + "sender": "Mittente", + + "senderKey": "Chiave mittente", + + "recipient": "Destinatario", + + "recipientKey": "Chiave destinatario", + + "voice": "Voce", + + "voiceId": "ID vocale", + + "envelope": "Busta", + + "sessionProgress": "Avanzamento sessione", + + "complete": "Completato", + + "rawDump": "Dump grezzo", + + "cannotRetryMissingRecipient": "Impossibile riprovare: informazioni destinatario mancanti", + + "voiceUnavailable": "Voce non disponibile al momento", + + "requestingVoice": "Richiesta voce" +} \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index b1c44e8..74fef0c 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -4054,6 +4054,156 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'No team contacts available'** String get noContactsAvailable; + + /// No description provided for @reply. + /// + /// In en, this message translates to: + /// **'Reply'** + String get reply; + + /// No description provided for @technicalDetails. + /// + /// In en, this message translates to: + /// **'Technical details'** + String get technicalDetails; + + /// No description provided for @messageTechnicalDetails. + /// + /// In en, this message translates to: + /// **'Message technical details'** + String get messageTechnicalDetails; + + /// No description provided for @linkQuality. + /// + /// In en, this message translates to: + /// **'Link quality'** + String get linkQuality; + + /// No description provided for @delivery. + /// + /// In en, this message translates to: + /// **'Delivery'** + String get delivery; + + /// No description provided for @status. + /// + /// In en, this message translates to: + /// **'Status'** + String get status; + + /// No description provided for @expectedAckTag. + /// + /// In en, this message translates to: + /// **'Expected ACK tag'** + String get expectedAckTag; + + /// No description provided for @roundTrip. + /// + /// In en, this message translates to: + /// **'Round-trip'** + String get roundTrip; + + /// No description provided for @retryAttempt. + /// + /// In en, this message translates to: + /// **'Retry attempt'** + String get retryAttempt; + + /// No description provided for @floodFallback. + /// + /// In en, this message translates to: + /// **'Flood fallback'** + String get floodFallback; + + /// No description provided for @identity. + /// + /// In en, this message translates to: + /// **'Identity'** + String get identity; + + /// No description provided for @messageId. + /// + /// In en, this message translates to: + /// **'Message ID'** + String get messageId; + + /// No description provided for @sender. + /// + /// In en, this message translates to: + /// **'Sender'** + String get sender; + + /// No description provided for @senderKey. + /// + /// In en, this message translates to: + /// **'Sender key'** + String get senderKey; + + /// No description provided for @recipient. + /// + /// In en, this message translates to: + /// **'Recipient'** + String get recipient; + + /// No description provided for @recipientKey. + /// + /// In en, this message translates to: + /// **'Recipient key'** + String get recipientKey; + + /// No description provided for @voice. + /// + /// In en, this message translates to: + /// **'Voice'** + String get voice; + + /// No description provided for @voiceId. + /// + /// In en, this message translates to: + /// **'Voice ID'** + String get voiceId; + + /// No description provided for @envelope. + /// + /// In en, this message translates to: + /// **'Envelope'** + String get envelope; + + /// No description provided for @sessionProgress. + /// + /// In en, this message translates to: + /// **'Session progress'** + String get sessionProgress; + + /// No description provided for @complete. + /// + /// In en, this message translates to: + /// **'Complete'** + String get complete; + + /// No description provided for @rawDump. + /// + /// In en, this message translates to: + /// **'Raw dump'** + String get rawDump; + + /// No description provided for @cannotRetryMissingRecipient. + /// + /// In en, this message translates to: + /// **'Cannot retry: recipient information missing'** + String get cannotRetryMissingRecipient; + + /// No description provided for @voiceUnavailable. + /// + /// In en, this message translates to: + /// **'Voice unavailable right now'** + String get voiceUnavailable; + + /// No description provided for @requestingVoice. + /// + /// In en, this message translates to: + /// **'Requesting voice'** + String get requestingVoice; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index c015052..e4f6555 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2275,4 +2275,80 @@ class AppLocalizationsDe extends AppLocalizations { @override String get noContactsAvailable => 'Keine Team-Kontakte verfügbar'; + + @override + String get reply => 'Antworten'; + + @override + String get technicalDetails => 'Technische Details'; + + @override + String get messageTechnicalDetails => 'Technische Nachrichtendetails'; + + @override + String get linkQuality => 'Verbindungsqualität'; + + @override + String get delivery => 'Zustellung'; + + @override + String get status => 'Status'; + + @override + String get expectedAckTag => 'Erwartetes ACK-Tag'; + + @override + String get roundTrip => 'Roundtrip'; + + @override + String get retryAttempt => 'Wiederholungsversuch'; + + @override + String get floodFallback => 'Flood-Fallback'; + + @override + String get identity => 'Identität'; + + @override + String get messageId => 'Nachrichten-ID'; + + @override + String get sender => 'Absender'; + + @override + String get senderKey => 'Absenderschlüssel'; + + @override + String get recipient => 'Empfänger'; + + @override + String get recipientKey => 'Empfängerschlüssel'; + + @override + String get voice => 'Sprachnachricht'; + + @override + String get voiceId => 'Sprach-ID'; + + @override + String get envelope => 'Umschlag'; + + @override + String get sessionProgress => 'Sitzungsfortschritt'; + + @override + String get complete => 'Vollständig'; + + @override + String get rawDump => 'Rohdaten'; + + @override + String get cannotRetryMissingRecipient => + 'Wiederholung nicht möglich: Empfängerinformationen fehlen'; + + @override + String get voiceUnavailable => 'Sprachnachricht momentan nicht verfügbar'; + + @override + String get requestingVoice => 'Sprachnachricht wird angefordert'; } diff --git a/lib/l10n/app_localizations_el.dart b/lib/l10n/app_localizations_el.dart index c122f87..49e66bd 100644 --- a/lib/l10n/app_localizations_el.dart +++ b/lib/l10n/app_localizations_el.dart @@ -2248,4 +2248,80 @@ class AppLocalizationsEl extends AppLocalizations { @override String get noContactsAvailable => 'No team contacts available'; + + @override + String get reply => 'Απάντηση'; + + @override + String get technicalDetails => 'Τεχνικές λεπτομέρειες'; + + @override + String get messageTechnicalDetails => 'Τεχνικές λεπτομέρειες μηνύματος'; + + @override + String get linkQuality => 'Ποιότητα σύνδεσης'; + + @override + String get delivery => 'Παράδοση'; + + @override + String get status => 'Κατάσταση'; + + @override + String get expectedAckTag => 'Αναμενόμενη ετικέτα ACK'; + + @override + String get roundTrip => 'Χρόνος μετ\' επιστροφής'; + + @override + String get retryAttempt => 'Απόπειρα επανάληψης'; + + @override + String get floodFallback => 'Εφεδρική πλημμύρα'; + + @override + String get identity => 'Ταυτότητα'; + + @override + String get messageId => 'Αναγνωριστικό μηνύματος'; + + @override + String get sender => 'Αποστολέας'; + + @override + String get senderKey => 'Κλειδί αποστολέα'; + + @override + String get recipient => 'Παραλήπτης'; + + @override + String get recipientKey => 'Κλειδί παραλήπτη'; + + @override + String get voice => 'Φωνή'; + + @override + String get voiceId => 'Αναγνωριστικό φωνής'; + + @override + String get envelope => 'Φάκελος'; + + @override + String get sessionProgress => 'Πρόοδος συνεδρίας'; + + @override + String get complete => 'Ολοκληρώθηκε'; + + @override + String get rawDump => 'Ακατέργαστα δεδομένα'; + + @override + String get cannotRetryMissingRecipient => + 'Δεν είναι δυνατή η επανάληψη: λείπουν πληροφορίες παραλήπτη'; + + @override + String get voiceUnavailable => 'Η φωνή δεν είναι διαθέσιμη αυτή τη στιγμή'; + + @override + String get requestingVoice => 'Αίτηση φωνής'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 3937a1d..04548db 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2248,4 +2248,80 @@ class AppLocalizationsEn extends AppLocalizations { @override String get noContactsAvailable => 'No team contacts available'; + + @override + String get reply => 'Reply'; + + @override + String get technicalDetails => 'Technical details'; + + @override + String get messageTechnicalDetails => 'Message technical details'; + + @override + String get linkQuality => 'Link quality'; + + @override + String get delivery => 'Delivery'; + + @override + String get status => 'Status'; + + @override + String get expectedAckTag => 'Expected ACK tag'; + + @override + String get roundTrip => 'Round-trip'; + + @override + String get retryAttempt => 'Retry attempt'; + + @override + String get floodFallback => 'Flood fallback'; + + @override + String get identity => 'Identity'; + + @override + String get messageId => 'Message ID'; + + @override + String get sender => 'Sender'; + + @override + String get senderKey => 'Sender key'; + + @override + String get recipient => 'Recipient'; + + @override + String get recipientKey => 'Recipient key'; + + @override + String get voice => 'Voice'; + + @override + String get voiceId => 'Voice ID'; + + @override + String get envelope => 'Envelope'; + + @override + String get sessionProgress => 'Session progress'; + + @override + String get complete => 'Complete'; + + @override + String get rawDump => 'Raw dump'; + + @override + String get cannotRetryMissingRecipient => + 'Cannot retry: recipient information missing'; + + @override + String get voiceUnavailable => 'Voice unavailable right now'; + + @override + String get requestingVoice => 'Requesting voice'; } diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 1d27cbb..acfb394 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2279,4 +2279,80 @@ class AppLocalizationsEs extends AppLocalizations { @override String get noContactsAvailable => 'No hay contactos del equipo disponibles'; + + @override + String get reply => 'Responder'; + + @override + String get technicalDetails => 'Detalles técnicos'; + + @override + String get messageTechnicalDetails => 'Detalles técnicos del mensaje'; + + @override + String get linkQuality => 'Calidad del enlace'; + + @override + String get delivery => 'Entrega'; + + @override + String get status => 'Estado'; + + @override + String get expectedAckTag => 'Etiqueta ACK esperada'; + + @override + String get roundTrip => 'Ida y vuelta'; + + @override + String get retryAttempt => 'Intento de reenvío'; + + @override + String get floodFallback => 'Reserva de inundación'; + + @override + String get identity => 'Identidad'; + + @override + String get messageId => 'ID de mensaje'; + + @override + String get sender => 'Remitente'; + + @override + String get senderKey => 'Clave del remitente'; + + @override + String get recipient => 'Destinatario'; + + @override + String get recipientKey => 'Clave del destinatario'; + + @override + String get voice => 'Voz'; + + @override + String get voiceId => 'ID de voz'; + + @override + String get envelope => 'Envolvente'; + + @override + String get sessionProgress => 'Progreso de sesión'; + + @override + String get complete => 'Completo'; + + @override + String get rawDump => 'Volcado sin procesar'; + + @override + String get cannotRetryMissingRecipient => + 'No se puede reintentar: falta información del destinatario'; + + @override + String get voiceUnavailable => 'Voz no disponible en este momento'; + + @override + String get requestingVoice => 'Solicitando voz'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index bd08705..1f88c90 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2285,4 +2285,80 @@ class AppLocalizationsFr extends AppLocalizations { @override String get noContactsAvailable => 'Aucun contact d\'équipe disponible'; + + @override + String get reply => 'Répondre'; + + @override + String get technicalDetails => 'Détails techniques'; + + @override + String get messageTechnicalDetails => 'Détails techniques du message'; + + @override + String get linkQuality => 'Qualité du lien'; + + @override + String get delivery => 'Livraison'; + + @override + String get status => 'Statut'; + + @override + String get expectedAckTag => 'Balise ACK attendue'; + + @override + String get roundTrip => 'Aller-retour'; + + @override + String get retryAttempt => 'Tentative de renvoi'; + + @override + String get floodFallback => 'Repli inondation'; + + @override + String get identity => 'Identité'; + + @override + String get messageId => 'ID du message'; + + @override + String get sender => 'Expéditeur'; + + @override + String get senderKey => 'Clé de l\'expéditeur'; + + @override + String get recipient => 'Destinataire'; + + @override + String get recipientKey => 'Clé du destinataire'; + + @override + String get voice => 'Voix'; + + @override + String get voiceId => 'ID vocal'; + + @override + String get envelope => 'Enveloppe'; + + @override + String get sessionProgress => 'Progression de session'; + + @override + String get complete => 'Complet'; + + @override + String get rawDump => 'Vidage brut'; + + @override + String get cannotRetryMissingRecipient => + 'Impossible de réessayer : informations du destinataire manquantes'; + + @override + String get voiceUnavailable => 'Voix indisponible pour le moment'; + + @override + String get requestingVoice => 'Demande de voix'; } diff --git a/lib/l10n/app_localizations_hr.dart b/lib/l10n/app_localizations_hr.dart index 48f6e71..e2887b9 100644 --- a/lib/l10n/app_localizations_hr.dart +++ b/lib/l10n/app_localizations_hr.dart @@ -2260,4 +2260,80 @@ class AppLocalizationsHr extends AppLocalizations { @override String get noContactsAvailable => 'Nema dostupnih kontakata tima'; + + @override + String get reply => 'Odgovori'; + + @override + String get technicalDetails => 'Tehnički detalji'; + + @override + String get messageTechnicalDetails => 'Tehnički detalji poruke'; + + @override + String get linkQuality => 'Kvaliteta veze'; + + @override + String get delivery => 'Dostava'; + + @override + String get status => 'Status'; + + @override + String get expectedAckTag => 'Očekivana ACK oznaka'; + + @override + String get roundTrip => 'Povratno putovanje'; + + @override + String get retryAttempt => 'Pokušaj ponovnog slanja'; + + @override + String get floodFallback => 'Flood rezerva'; + + @override + String get identity => 'Identitet'; + + @override + String get messageId => 'ID poruke'; + + @override + String get sender => 'Pošiljatelj'; + + @override + String get senderKey => 'Ključ pošiljatelja'; + + @override + String get recipient => 'Primatelj'; + + @override + String get recipientKey => 'Ključ primatelja'; + + @override + String get voice => 'Glas'; + + @override + String get voiceId => 'ID glasa'; + + @override + String get envelope => 'Omotnica'; + + @override + String get sessionProgress => 'Napredak sesije'; + + @override + String get complete => 'Dovršeno'; + + @override + String get rawDump => 'Sirovi ispis'; + + @override + String get cannotRetryMissingRecipient => + 'Nije moguće ponoviti: nedostaju informacije o primatelju'; + + @override + String get voiceUnavailable => 'Glas trenutno nije dostupan'; + + @override + String get requestingVoice => 'Zahtjev za glasom'; } diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index b62a61f..35f39ba 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2274,4 +2274,80 @@ class AppLocalizationsIt extends AppLocalizations { @override String get noContactsAvailable => 'Nessun contatto del team disponibile'; + + @override + String get reply => 'Rispondi'; + + @override + String get technicalDetails => 'Dettagli tecnici'; + + @override + String get messageTechnicalDetails => 'Dettagli tecnici del messaggio'; + + @override + String get linkQuality => 'Qualità del collegamento'; + + @override + String get delivery => 'Consegna'; + + @override + String get status => 'Stato'; + + @override + String get expectedAckTag => 'Tag ACK atteso'; + + @override + String get roundTrip => 'Andata e ritorno'; + + @override + String get retryAttempt => 'Tentativo di nuovo invio'; + + @override + String get floodFallback => 'Fallback inondazione'; + + @override + String get identity => 'Identità'; + + @override + String get messageId => 'ID messaggio'; + + @override + String get sender => 'Mittente'; + + @override + String get senderKey => 'Chiave mittente'; + + @override + String get recipient => 'Destinatario'; + + @override + String get recipientKey => 'Chiave destinatario'; + + @override + String get voice => 'Voce'; + + @override + String get voiceId => 'ID vocale'; + + @override + String get envelope => 'Busta'; + + @override + String get sessionProgress => 'Avanzamento sessione'; + + @override + String get complete => 'Completato'; + + @override + String get rawDump => 'Dump grezzo'; + + @override + String get cannotRetryMissingRecipient => + 'Impossibile riprovare: informazioni destinatario mancanti'; + + @override + String get voiceUnavailable => 'Voce non disponibile al momento'; + + @override + String get requestingVoice => 'Richiesta voce'; } diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 4bed713..9fa9c77 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2262,4 +2262,80 @@ class AppLocalizationsSl extends AppLocalizations { @override String get noContactsAvailable => 'Ni razpoložljivih stikov ekipe'; + + @override + String get reply => 'Odgovori'; + + @override + String get technicalDetails => 'Tehnični podrobnosti'; + + @override + String get messageTechnicalDetails => 'Tehnični podrobnosti sporočila'; + + @override + String get linkQuality => 'Kakovost povezave'; + + @override + String get delivery => 'Dostava'; + + @override + String get status => 'Status'; + + @override + String get expectedAckTag => 'Pričakovana oznaka ACK'; + + @override + String get roundTrip => 'Povratna pot'; + + @override + String get retryAttempt => 'Poskus ponovnega pošiljanja'; + + @override + String get floodFallback => 'Flood rezerva'; + + @override + String get identity => 'Identiteta'; + + @override + String get messageId => 'ID sporočila'; + + @override + String get sender => 'Pošiljatelj'; + + @override + String get senderKey => 'Ključ pošiljatelja'; + + @override + String get recipient => 'Prejemnik'; + + @override + String get recipientKey => 'Ključ prejemnika'; + + @override + String get voice => 'Glas'; + + @override + String get voiceId => 'ID glasu'; + + @override + String get envelope => 'Ovojnica'; + + @override + String get sessionProgress => 'Napredek seje'; + + @override + String get complete => 'Dokončano'; + + @override + String get rawDump => 'Surovi izpis'; + + @override + String get cannotRetryMissingRecipient => + 'Ponovnega pošiljanja ni mogoče: informacije o prejemniku manjkajo'; + + @override + String get voiceUnavailable => 'Glas trenutno ni na voljo'; + + @override + String get requestingVoice => 'Zahteva za glasom'; } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 60b39f8..9b8394a 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1107,4 +1107,55 @@ "directMessagesInfo": "Neposredna sporočila s potrditvami. Poslano {count} članom ekipe.", "sarMarkerSentToContacts": "SAR označevalec poslan {count} stikom", "noContactsAvailable": "Ni razpoložljivih stikov ekipe" -} +, + + "reply": "Odgovori", + + "technicalDetails": "Tehnični podrobnosti", + + "messageTechnicalDetails": "Tehnični podrobnosti sporočila", + + "linkQuality": "Kakovost povezave", + + "delivery": "Dostava", + + "status": "Status", + + "expectedAckTag": "Pričakovana oznaka ACK", + + "roundTrip": "Povratna pot", + + "retryAttempt": "Poskus ponovnega pošiljanja", + + "floodFallback": "Flood rezerva", + + "identity": "Identiteta", + + "messageId": "ID sporočila", + + "sender": "Pošiljatelj", + + "senderKey": "Ključ pošiljatelja", + + "recipient": "Prejemnik", + + "recipientKey": "Ključ prejemnika", + + "voice": "Glas", + + "voiceId": "ID glasu", + + "envelope": "Ovojnica", + + "sessionProgress": "Napredek seje", + + "complete": "Dokončano", + + "rawDump": "Surovi izpis", + + "cannotRetryMissingRecipient": "Ponovnega pošiljanja ni mogoče: informacije o prejemniku manjkajo", + + "voiceUnavailable": "Glas trenutno ni na voljo", + + "requestingVoice": "Zahteva za glasom" +} \ No newline at end of file diff --git a/lib/screens/messages_tab.dart b/lib/screens/messages_tab.dart index 22a7d45..1308fd3 100644 --- a/lib/screens/messages_tab.dart +++ b/lib/screens/messages_tab.dart @@ -58,7 +58,7 @@ class _MessagesTabState extends State { static const double _silenceRmsThreshold = 500.0; static const double _silencePeakThreshold = 1400.0; static const int _maxInteriorSilentChunks = 1; - bool get _voiceSupported => Platform.isIOS; + bool get _voiceSupported => Platform.isIOS || Platform.isAndroid; StreamSubscription? _voiceStreamSub; String? _currentVoiceSessionId; final List _recordedChunks = []; diff --git a/lib/services/voice_codec_service.dart b/lib/services/voice_codec_service.dart index 9435dfa..cebaba5 100644 --- a/lib/services/voice_codec_service.dart +++ b/lib/services/voice_codec_service.dart @@ -32,8 +32,10 @@ VoicePacketMode voiceModeForBandwidth(int radioBandwidthHz) { /// executed in a background isolate so the UI thread is never blocked. class VoiceCodecService { void _ensureCodec2Supported() { - if (kIsWeb || defaultTargetPlatform != TargetPlatform.iOS) { - throw UnsupportedError('Codec2 is enabled only on iOS.'); + if (kIsWeb || + (defaultTargetPlatform != TargetPlatform.iOS && + defaultTargetPlatform != TargetPlatform.android)) { + throw UnsupportedError('Codec2 is enabled only on iOS and Android.'); } } diff --git a/lib/widgets/messages/message_bubble.dart b/lib/widgets/messages/message_bubble.dart index 2ee14df..77d382b 100644 --- a/lib/widgets/messages/message_bubble.dart +++ b/lib/widgets/messages/message_bubble.dart @@ -104,7 +104,7 @@ class _MessageBubbleState extends State { messagesProvider.markMessageFailed(retryMessageId); ToastLogger.error( context, - 'Cannot retry: recipient information missing', + AppLocalizations.of(context)!.cannotRetryMissingRecipient, ); return; } @@ -176,7 +176,7 @@ class _MessageBubbleState extends State { if (canReply) ListTile( leading: const Icon(Icons.reply), - title: const Text('Reply'), + title: Text(AppLocalizations.of(context)!.reply), onTap: () { Navigator.pop(context); _showReplySheet(context); @@ -269,7 +269,7 @@ class _MessageBubbleState extends State { // Technical details option ListTile( leading: const Icon(Icons.data_object), - title: const Text('Technical details'), + title: Text(AppLocalizations.of(context)!.technicalDetails), onTap: () { Navigator.pop(context); _showTechnicalDetails(context); @@ -427,15 +427,17 @@ class _MessageBubbleState extends State { } } - void copyField(String label, String value) { + final l10n = AppLocalizations.of(context)!; + + void copyField(String value) { Clipboard.setData(ClipboardData(text: value)); - ToastLogger.success(context, '$label copied'); + ToastLogger.success(context, l10n.textCopiedToClipboard); } showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Message technical details'), + title: Text(l10n.messageTechnicalDetails), content: SizedBox( width: double.maxFinite, child: SingleChildScrollView( @@ -477,7 +479,7 @@ class _MessageBubbleState extends State { _techSection( context, icon: Icons.network_check, - title: 'Link quality', + title: l10n.linkQuality, child: Column( children: [ if (widget.message.lastEchoRssiDbm != null) @@ -518,35 +520,35 @@ class _MessageBubbleState extends State { _techSection( context, icon: Icons.tune, - title: 'Delivery', + title: l10n.delivery, child: Column( children: [ _detailRow( context, - label: 'Status', + label: l10n.status, value: widget.message.deliveryStatus.name, ), _detailRow( context, - label: 'Expected ACK tag', + label: l10n.expectedAckTag, value: widget.message.expectedAckTag?.toString() ?? '-', ), _detailRow( context, - label: 'Round-trip', + label: l10n.roundTrip, value: widget.message.roundTripTimeMs != null ? '${widget.message.roundTripTimeMs} ms' : '-', ), _detailRow( context, - label: 'Retry attempt', + label: l10n.retryAttempt, value: widget.message.retryAttempt.toString(), ), _detailRow( context, - label: 'Flood fallback', - value: widget.message.usedFloodFallback ? 'Yes' : 'No', + label: l10n.floodFallback, + value: widget.message.usedFloodFallback ? l10n.yes : l10n.no, ), ], ), @@ -555,41 +557,39 @@ class _MessageBubbleState extends State { _techSection( context, icon: Icons.badge, - title: 'Identity', + title: l10n.identity, child: Column( children: [ _detailRow( context, - label: 'Message ID', + label: l10n.messageId, value: widget.message.id, - onCopy: () => - copyField('Message ID', widget.message.id), + onCopy: () => copyField(widget.message.id), ), _detailRow( context, - label: 'Sender', + label: l10n.sender, value: senderName ?? widget.message.senderName ?? '-', ), _detailRow( context, - label: 'Sender key', + label: l10n.senderKey, value: senderPrefixHex ?? '-', onCopy: senderPrefixHex != null - ? () => copyField('Sender key', senderPrefixHex) + ? () => copyField(senderPrefixHex) : null, ), _detailRow( context, - label: 'Recipient', + label: l10n.recipient, value: recipientName ?? '-', ), _detailRow( context, - label: 'Recipient key', + label: l10n.recipientKey, value: recipientPrefixHex ?? '-', onCopy: recipientPrefixHex != null - ? () => - copyField('Recipient key', recipientPrefixHex) + ? () => copyField(recipientPrefixHex) : null, ), ], @@ -600,35 +600,35 @@ class _MessageBubbleState extends State { _techSection( context, icon: Icons.graphic_eq, - title: 'Voice', + title: l10n.voice, child: Column( children: [ _detailRow( context, - label: 'Voice ID', + label: l10n.voiceId, value: widget.message.voiceId ?? '-', ), _detailRow( context, - label: 'Envelope', + label: l10n.envelope, value: envelope != null ? 'VE1 compact' : legacyVoicePacket != null ? 'Legacy V packet' - : 'Unknown', + : l10n.unknown, ), if (voiceSession != null) _detailRow( context, - label: 'Session progress', + label: l10n.sessionProgress, value: '${voiceSession.receivedCount}/${voiceSession.total} segments', ), if (voiceSession != null) _detailRow( context, - label: 'Complete', - value: voiceSession.isComplete ? 'Yes' : 'No', + label: l10n.complete, + value: voiceSession.isComplete ? l10n.yes : l10n.no, ), ], ), @@ -639,9 +639,9 @@ class _MessageBubbleState extends State { tilePadding: EdgeInsets.zero, dense: true, visualDensity: VisualDensity.compact, - title: const Text( - 'Raw dump', - style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600), + title: Text( + l10n.rawDump, + style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w600), ), children: [ Container( diff --git a/lib/widgets/messages/voice_message_bubble.dart b/lib/widgets/messages/voice_message_bubble.dart index fd02398..ae0e040 100644 --- a/lib/widgets/messages/voice_message_bubble.dart +++ b/lib/widgets/messages/voice_message_bubble.dart @@ -1,6 +1,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../../l10n/app_localizations.dart'; import '../../models/contact.dart'; import '../../models/message.dart'; import '../../providers/connection_provider.dart'; @@ -137,6 +138,7 @@ class _VoiceMessageBubbleState extends State { isComplete: isComplete, isRequesting: _isRequesting, errorText: _errorText, + requestingLabel: AppLocalizations.of(context)!.requestingVoice, ), style: TextStyle( fontSize: 11, @@ -200,7 +202,7 @@ class _VoiceMessageBubbleState extends State { setState(() { _isRequesting = false; _autoPlayWhenReady = false; - _errorText = 'Voice unavailable right now'; + _errorText = AppLocalizations.of(context)!.voiceUnavailable; }); } @@ -239,11 +241,12 @@ class _VoiceMessageBubbleState extends State { required bool isComplete, required bool isRequesting, required String? errorText, + required String requestingLabel, }) { if (errorText != null) return errorText; final progress = total > 0 ? ' ($received/$total)' : ''; if (isRequesting) { - return 'Requesting voice$progress'; + return '$requestingLabel$progress'; } if (!isComplete && total > 0) { return '🎙️ $durationLabel · $modeLabel$progress';