diff --git a/assets/icons/done_all.svg b/assets/icons/done_all.svg new file mode 100644 index 0000000..bfeeec0 --- /dev/null +++ b/assets/icons/done_all.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index dc0ca4e..e9f46c6 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1554,6 +1554,8 @@ "contacts_clipboardEmpty": "Клипборда е празна.", "contacts_invalidAdvertFormat": "Невалидни данни за контакт", "appSettings_languageRu": "Руски", + "appSettings_enableMessageTracing": "Разрешаване на проследяване на съобщения", + "appSettings_enableMessageTracingSubtitle": "Показване на подробни метаданни за маршрутизация и синхронизация за съобщения", "contacts_contactImported": "Контактът е импортиран.", "contacts_zeroHopAdvert": "Реклама без скок", "contacts_contactImportFailed": "Контактът не е успешно импортиран.", @@ -1716,21 +1718,5 @@ "losPointName": "Име на точката", "losShowPanelTooltip": "Показване на LOS панел", "losHidePanelTooltip": "Скриване на LOS панела", - "losElevationAttribution": "Данни за надморска височина: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Радиохоризонт", - "losLegendLosBeam": "LOS лъч", - "losLegendTerrain": "Терен", - "losFrequencyLabel": "Честота", - "losFrequencyInfoTooltip": "Преглед на подробностите за изчислението", - "losFrequencyDialogTitle": "Изчисление на радиохоризонта", - "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {baselineFreq} MHz, изчислението умножава 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, за да достигне k approx {kFactor} за текущата лента {frequencyMHz} MHz, която определя извитата граница на радиохоризонта.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Данни за надморска височина: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 25c899c..bdea574 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1554,6 +1554,8 @@ "contacts_invalidAdvertFormat": "Ungültige Kontaktdaten", "contacts_clipboardEmpty": "Die Zwischenablage ist leer.", "appSettings_languageUk": "Ukrainisch", + "appSettings_enableMessageTracing": "Nachrichtenverfolgung aktivieren", + "appSettings_enableMessageTracingSubtitle": "Detaillierte Routing- und Timing-Metadaten für Nachrichten anzeigen", "contacts_contactImported": "Kontakt wurde importiert.", "contacts_contactImportFailed": "Kontakt konnte nicht importiert werden", "contacts_zeroHopAdvert": "Zero-Hop-Ankündigung", @@ -1744,21 +1746,5 @@ "losPointName": "Punktname", "losShowPanelTooltip": "LOS-Panel anzeigen", "losHidePanelTooltip": "LOS-Panel ausblenden", - "losElevationAttribution": "Höhendaten: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Funkhorizont", - "losLegendLosBeam": "LOS-Strahl", - "losLegendTerrain": "Gelände", - "losFrequencyLabel": "Frequenz", - "losFrequencyInfoTooltip": "Berechnungsdetails anzeigen", - "losFrequencyDialogTitle": "Funkhorizont-Berechnung", - "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {baselineFreq} MHz multipliziert die Berechnung 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, um k approx {kFactor} für das aktuelle {frequencyMHz}-MHz-Band zu erreichen, das die gekrümmte Funkhorizont-Grenze definiert.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Höhendaten: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3f89e48..99ce9e2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -183,6 +183,8 @@ "appSettings_languageBg": "Български", "appSettings_languageRu": "Русский", "appSettings_languageUk": "Українська", + "appSettings_enableMessageTracing": "Enable Message Tracing", + "appSettings_enableMessageTracingSubtitle": "Show detailed routing and timing metadata for messages", "appSettings_notifications": "Notifications", "appSettings_enableNotifications": "Enable Notifications", "appSettings_enableNotificationsSubtitle": "Receive notifications for messages and adverts", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 0616454..99db15d 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1553,6 +1553,8 @@ "appSettings_languageUk": "Ucraniano", "contacts_clipboardEmpty": "El portapapeles está vacío.", "appSettings_languageRu": "Ruso", + "appSettings_enableMessageTracing": "Habilitar seguimiento de mensajes", + "appSettings_enableMessageTracingSubtitle": "Mostrar metadatos detallados de enrutamiento y tiempo para los mensajes", "contacts_invalidAdvertFormat": "Datos de contacto no válidos", "contacts_floodAdvert": "Anuncio de inundación", "contacts_contactImported": "El contacto ha sido importado.", @@ -1744,21 +1746,5 @@ "losPointName": "Nombre del punto", "losShowPanelTooltip": "Mostrar panel LOS", "losHidePanelTooltip": "Ocultar panel LOS", - "losElevationAttribution": "Datos de elevación: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Horizonte radioeléctrico", - "losLegendLosBeam": "Haz LOS", - "losLegendTerrain": "Terreno", - "losFrequencyLabel": "Frecuencia", - "losFrequencyInfoTooltip": "Ver detalles del cálculo", - "losFrequencyDialogTitle": "Cálculo del horizonte radioeléctrico", - "losFrequencyDialogDescription": "Partiendo de k={baselineK} a {baselineFreq} MHz, el cálculo multiplica 0.15 × (frequency − {baselineFreq}) / {baselineFreq} para llegar a k approx {kFactor} para la banda actual de {frequencyMHz} MHz, que define el límite curvo del horizonte radioeléctrico.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Datos de elevación: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index cfdd3ba..bc82195 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1553,6 +1553,8 @@ "contacts_invalidAdvertFormat": "Données de contact non valides", "appSettings_languageUk": "Ukrainien", "appSettings_languageRu": "Russe", + "appSettings_enableMessageTracing": "Activer le traçage des messages", + "appSettings_enableMessageTracingSubtitle": "Afficher les métadonnées détaillées de routage et de synchronisation des messages", "contacts_clipboardEmpty": "Le presse-papiers est vide.", "contacts_contactImported": "Le contact a été importé.", "contacts_floodAdvert": "Annonce à tout le réseau", @@ -1716,21 +1718,5 @@ "losPointName": "Nom du point", "losShowPanelTooltip": "Afficher le panneau LOS", "losHidePanelTooltip": "Masquer le panneau LOS", - "losElevationAttribution": "Données d'altitude : Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Horizon radio", - "losLegendLosBeam": "Faisceau LOS", - "losLegendTerrain": "Terrain", - "losFrequencyLabel": "Fréquence", - "losFrequencyInfoTooltip": "Voir les détails du calcul", - "losFrequencyDialogTitle": "Calcul de l’horizon radio", - "losFrequencyDialogDescription": "En partant de k={baselineK} à {baselineFreq} MHz, le calcul multiplie 0.15 × (frequency − {baselineFreq}) / {baselineFreq} pour atteindre k approx {kFactor} pour la bande actuelle de {frequencyMHz} MHz, qui définit la limite courbe de l’horizon radio.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Données d'altitude : Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 427eb0a..fe4bffc 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1553,6 +1553,8 @@ "appSettings_languageRu": "Russo", "contacts_invalidAdvertFormat": "Dati di contatto non validi", "appSettings_languageUk": "Ucraino", + "appSettings_enableMessageTracing": "Abilita tracciamento messaggi", + "appSettings_enableMessageTracingSubtitle": "Mostra metadati dettagliati su instradamento e tempi per i messaggi", "contacts_zeroHopAdvert": "Annuncio Zero Hop", "contacts_floodAdvert": "Annuncio alluvionale", "contacts_copyAdvertToClipboard": "Copia Annuncio negli Appunti", @@ -1716,21 +1718,5 @@ "losPointName": "Nome del punto", "losShowPanelTooltip": "Mostra il pannello LOS", "losHidePanelTooltip": "Nascondi il pannello LOS", - "losElevationAttribution": "Dati di elevazione: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Orizzonte radio", - "losLegendLosBeam": "Raggio LOS", - "losLegendTerrain": "Terreno", - "losFrequencyLabel": "Frequenza", - "losFrequencyInfoTooltip": "Visualizza i dettagli del calcolo", - "losFrequencyDialogTitle": "Calcolo dell’orizzonte radio", - "losFrequencyDialogDescription": "Partendo da k={baselineK} a {baselineFreq} MHz, il calcolo moltiplica 0.15 × (frequency − {baselineFreq}) / {baselineFreq} per raggiungere k approx {kFactor} per la banda corrente di {frequencyMHz} MHz, che definisce il limite curvo dell’orizzonte radio.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Dati di elevazione: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 015dcca..1996ad6 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -970,6 +970,18 @@ abstract class AppLocalizations { /// **'Українська'** String get appSettings_languageUk; + /// No description provided for @appSettings_enableMessageTracing. + /// + /// In en, this message translates to: + /// **'Enable Message Tracing'** + String get appSettings_enableMessageTracing; + + /// No description provided for @appSettings_enableMessageTracingSubtitle. + /// + /// In en, this message translates to: + /// **'Show detailed routing and timing metadata for messages'** + String get appSettings_enableMessageTracingSubtitle; + /// No description provided for @appSettings_notifications. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 68ed8e5..7da0714 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -466,6 +466,14 @@ class AppLocalizationsBg extends AppLocalizations { @override String get appSettings_languageUk => 'Украински'; + @override + String get appSettings_enableMessageTracing => + 'Разрешаване на проследяване на съобщения'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Показване на подробни метаданни за маршрутизация и синхронизация за съобщения'; + @override String get appSettings_notifications => 'Уведомления'; @@ -2860,23 +2868,22 @@ class AppLocalizationsBg extends AppLocalizations { 'Данни за надморска височина: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Радиохоризонт'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS лъч'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Терен'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Честота'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => - 'Преглед на подробностите за изчислението'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Изчисление на радиохоризонта'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2885,7 +2892,7 @@ class AppLocalizationsBg extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Започвайки от k=$baselineK при $baselineFreq MHz, изчислението умножава 0.15 × (frequency − $baselineFreq) / $baselineFreq, за да достигне k approx $kFactor за текущата лента $frequencyMHz MHz, която определя извитата граница на радиохоризонта.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 1c97a4c..b81565c 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -460,6 +460,14 @@ class AppLocalizationsDe extends AppLocalizations { @override String get appSettings_languageUk => 'Ukrainisch'; + @override + String get appSettings_enableMessageTracing => + 'Nachrichtenverfolgung aktivieren'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Detaillierte Routing- und Timing-Metadaten für Nachrichten anzeigen'; + @override String get appSettings_notifications => 'Benachrichtigungen'; @@ -2866,22 +2874,22 @@ class AppLocalizationsDe extends AppLocalizations { String get losElevationAttribution => 'Höhendaten: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Funkhorizont'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS-Strahl'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Gelände'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frequenz'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Berechnungsdetails anzeigen'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Funkhorizont-Berechnung'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2890,7 +2898,7 @@ class AppLocalizationsDe extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Ausgehend von k=$baselineK bei $baselineFreq MHz multipliziert die Berechnung 0.15 × (frequency − $baselineFreq) / $baselineFreq, um k approx $kFactor für das aktuelle $frequencyMHz-MHz-Band zu erreichen, das die gekrümmte Funkhorizont-Grenze definiert.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index c5ef344..5c7cf36 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -458,6 +458,13 @@ class AppLocalizationsEn extends AppLocalizations { @override String get appSettings_languageUk => 'Українська'; + @override + String get appSettings_enableMessageTracing => 'Enable Message Tracing'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Show detailed routing and timing metadata for messages'; + @override String get appSettings_notifications => 'Notifications'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 33db872..971d9d3 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -463,6 +463,14 @@ class AppLocalizationsEs extends AppLocalizations { @override String get appSettings_languageUk => 'Ucraniano'; + @override + String get appSettings_enableMessageTracing => + 'Habilitar seguimiento de mensajes'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Mostrar metadatos detallados de enrutamiento y tiempo para los mensajes'; + @override String get appSettings_notifications => 'Notificaciones'; @@ -2860,22 +2868,22 @@ class AppLocalizationsEs extends AppLocalizations { 'Datos de elevación: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Horizonte radioeléctrico'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Haz LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terreno'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frecuencia'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Ver detalles del cálculo'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Cálculo del horizonte radioeléctrico'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2884,7 +2892,7 @@ class AppLocalizationsEs extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Partiendo de k=$baselineK a $baselineFreq MHz, el cálculo multiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq para llegar a k approx $kFactor para la banda actual de $frequencyMHz MHz, que define el límite curvo del horizonte radioeléctrico.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index fc059a9..1627987 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -464,6 +464,14 @@ class AppLocalizationsFr extends AppLocalizations { @override String get appSettings_languageUk => 'Ukrainien'; + @override + String get appSettings_enableMessageTracing => + 'Activer le traçage des messages'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Afficher les métadonnées détaillées de routage et de synchronisation des messages'; + @override String get appSettings_notifications => 'Notifications'; @@ -2875,22 +2883,22 @@ class AppLocalizationsFr extends AppLocalizations { 'Données d\'altitude : Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Horizon radio'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Faisceau LOS'; + String get losLegendLosBeam => 'LOS beam'; @override String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Fréquence'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Voir les détails du calcul'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Calcul de l’horizon radio'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2899,7 +2907,7 @@ class AppLocalizationsFr extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'En partant de k=$baselineK à $baselineFreq MHz, le calcul multiplie 0.15 × (frequency − $baselineFreq) / $baselineFreq pour atteindre k approx $kFactor pour la bande actuelle de $frequencyMHz MHz, qui définit la limite courbe de l’horizon radio.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 123d194..dccc31a 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -462,6 +462,14 @@ class AppLocalizationsIt extends AppLocalizations { @override String get appSettings_languageUk => 'Ucraino'; + @override + String get appSettings_enableMessageTracing => + 'Abilita tracciamento messaggi'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Mostra metadati dettagliati su instradamento e tempi per i messaggi'; + @override String get appSettings_notifications => 'Notifiche'; @@ -2860,22 +2868,22 @@ class AppLocalizationsIt extends AppLocalizations { 'Dati di elevazione: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Orizzonte radio'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Raggio LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terreno'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frequenza'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Visualizza i dettagli del calcolo'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Calcolo dell’orizzonte radio'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2884,7 +2892,7 @@ class AppLocalizationsIt extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Partendo da k=$baselineK a $baselineFreq MHz, il calcolo moltiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq per raggiungere k approx $kFactor per la banda corrente di $frequencyMHz MHz, che definisce il limite curvo dell’orizzonte radio.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 3c6d5c4..b02ffa7 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -460,6 +460,13 @@ class AppLocalizationsNl extends AppLocalizations { @override String get appSettings_languageUk => 'Oekraïens'; + @override + String get appSettings_enableMessageTracing => 'Berichttracking inschakelen'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Gedetailleerde routerings- en timing-metadata voor berichten weergeven'; + @override String get appSettings_notifications => 'Notificaties'; @@ -2851,22 +2858,22 @@ class AppLocalizationsNl extends AppLocalizations { 'Hoogtegegevens: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radiohorizon'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS-straal'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terrein'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frequentie'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Berekeningsdetails bekijken'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Radiohorizon-berekening'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2875,7 +2882,7 @@ class AppLocalizationsNl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Uitgaande van k=$baselineK bij $baselineFreq MHz vermenigvuldigt de berekening 0.15 × (frequency − $baselineFreq) / $baselineFreq om k approx $kFactor te bereiken voor de huidige $frequencyMHz-MHz-band, die de gebogen radiohorizon-limiet definieert.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 02a6a11..b8e2705 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -464,6 +464,13 @@ class AppLocalizationsPl extends AppLocalizations { @override String get appSettings_languageUk => 'Ukraińska'; + @override + String get appSettings_enableMessageTracing => 'Włącz śledzenie wiadomości'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Pokaż szczegółowe metadane trasowania i czasu dla wiadomości'; + @override String get appSettings_notifications => 'Powiadomienia'; @@ -2857,22 +2864,22 @@ class AppLocalizationsPl extends AppLocalizations { 'Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Horyzont radiowy'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Wiązka LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Teren'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Częstotliwość'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Zobacz szczegóły obliczeń'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Obliczanie horyzontu radiowego'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2881,7 +2888,7 @@ class AppLocalizationsPl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Wychodząc od k=$baselineK przy $baselineFreq MHz, obliczenie mnoży 0.15 × (frequency − $baselineFreq) / $baselineFreq, aby osiągnąć k approx $kFactor dla bieżącego pasma $frequencyMHz MHz, które definiuje zakrzywioną granicę horyzontu radiowego.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 7cb0986..b492c33 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -464,6 +464,14 @@ class AppLocalizationsPt extends AppLocalizations { @override String get appSettings_languageUk => 'Ucraniano'; + @override + String get appSettings_enableMessageTracing => + 'Ativar rastreamento de mensagens'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Mostrar metadados detalhados de roteamento e tempo para as mensagens'; + @override String get appSettings_notifications => 'Notificações'; @@ -2859,22 +2867,22 @@ class AppLocalizationsPt extends AppLocalizations { 'Dados de elevação: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Horizonte de rádio'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Feixe LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terreno'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frequência'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Ver detalhes do cálculo'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Cálculo do horizonte de rádio'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2883,7 +2891,7 @@ class AppLocalizationsPt extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Partindo de k=$baselineK a $baselineFreq MHz, o cálculo multiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq para chegar a k approx $kFactor para a banda atual de $frequencyMHz MHz, que define o limite curvo do horizonte de rádio.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 6e35b43..383bf09 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -462,6 +462,14 @@ class AppLocalizationsRu extends AppLocalizations { @override String get appSettings_languageUk => 'Українська'; + @override + String get appSettings_enableMessageTracing => + 'Включить трассировку сообщений'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Показывать подробные метаданные о маршрутизации и времени для сообщений'; + @override String get appSettings_notifications => 'Уведомления'; @@ -2862,22 +2870,22 @@ class AppLocalizationsRu extends AppLocalizations { 'Данные о высоте: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Радиогоризонт'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Луч LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Рельеф'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Частота'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Просмотреть детали расчёта'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Расчёт радиогоризонта'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2886,7 +2894,7 @@ class AppLocalizationsRu extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Исходя из k=$baselineK при $baselineFreq MHz, расчёт умножает 0.15 × (frequency − $baselineFreq) / $baselineFreq, чтобы получить k approx $kFactor для текущего диапазона $frequencyMHz MHz, который определяет изогнутую границу радиогоризонта.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 041e7fd..474cf32 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -460,6 +460,13 @@ class AppLocalizationsSk extends AppLocalizations { @override String get appSettings_languageUk => 'Ukrajinská'; + @override + String get appSettings_enableMessageTracing => 'Povoliť sledovanie správ'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Zobraziť podrobné metadáta o smerovaní a časovaní správ'; + @override String get appSettings_notifications => 'Upozornenia'; @@ -2845,22 +2852,22 @@ class AppLocalizationsSk extends AppLocalizations { 'Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Rádiový horizont'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS lúč'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terén'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frekvencia'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Zobraziť podrobnosti výpočtu'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Výpočet rádiového horizontu'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2869,7 +2876,7 @@ class AppLocalizationsSk extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Vychádzajúc z k=$baselineK pri $baselineFreq MHz výpočet násobí 0.15 × (frequency − $baselineFreq) / $baselineFreq, aby dosiahol k approx $kFactor pre aktuálne pásmo $frequencyMHz MHz, ktoré definuje zakrivenú hranicu rádiového horizontu.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 0a46533..6662bc1 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -459,6 +459,13 @@ class AppLocalizationsSl extends AppLocalizations { @override String get appSettings_languageUk => 'Ukrajinsko'; + @override + String get appSettings_enableMessageTracing => 'Omogoči sledenje sporočilom'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Prikaži podrobne metapodatke o usmerjanju in časovnem usklajevanju sporočil'; + @override String get appSettings_notifications => 'Obvestila'; @@ -2848,22 +2855,22 @@ class AppLocalizationsSl extends AppLocalizations { 'Podatki o višini: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radijski horizont'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS žarek'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Teren'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frekvenca'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Prikaži podrobnosti izračuna'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Izračun radijskega horizonta'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2872,7 +2879,7 @@ class AppLocalizationsSl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Izhajajoč iz k=$baselineK pri $baselineFreq MHz izračun množi 0.15 × (frequency − $baselineFreq) / $baselineFreq, da doseže k approx $kFactor za trenutno $frequencyMHz-MHz območje, ki določa ukrivljeno mejo radijskega horizonta.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 0fb8e70..35a532b 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -457,6 +457,13 @@ class AppLocalizationsSv extends AppLocalizations { @override String get appSettings_languageUk => 'Ukrainska'; + @override + String get appSettings_enableMessageTracing => 'Aktivera meddelandespårning'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Visa detaljerade metadata om dirigering och tidsinställningar för meddelanden'; + @override String get appSettings_notifications => 'Meddelanden'; @@ -2831,22 +2838,22 @@ class AppLocalizationsSv extends AppLocalizations { String get losElevationAttribution => 'Höjddata: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radiohorisont'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS-stråle'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Terräng'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frekvens'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Visa beräkningsdetaljer'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Beräkning av radiohorisont'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2855,7 +2862,7 @@ class AppLocalizationsSv extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Med start från k=$baselineK vid $baselineFreq MHz multiplicerar beräkningen 0.15 × (frequency − $baselineFreq) / $baselineFreq för att nå k approx $kFactor för det aktuella $frequencyMHz-MHz-bandet, vilket definierar den krökta radiohorisontgränsen.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index e81f8e1..4e7130b 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -462,6 +462,14 @@ class AppLocalizationsUk extends AppLocalizations { @override String get appSettings_languageUk => 'Українська'; + @override + String get appSettings_enableMessageTracing => + 'Увімкнути відстеження повідомлень'; + + @override + String get appSettings_enableMessageTracingSubtitle => + 'Показувати детальні метадані про маршрутизацію та час для повідомлень'; + @override String get appSettings_notifications => 'Сповіщення'; @@ -2870,22 +2878,22 @@ class AppLocalizationsUk extends AppLocalizations { 'Дані про висоту: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Радіогоризонт'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'Промінь LOS'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => 'Рельєф'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Частота'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => 'Переглянути деталі розрахунку'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => 'Розрахунок радіогоризонту'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2894,7 +2902,7 @@ class AppLocalizationsUk extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Виходячи з k=$baselineK при $baselineFreq MHz, розрахунок множить 0.15 × (frequency − $baselineFreq) / $baselineFreq, щоб отримати k approx $kFactor для поточного діапазону $frequencyMHz MHz, який визначає вигнуту межу радіогоризонту.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index a7f4a8a..2ecf38e 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -446,6 +446,12 @@ class AppLocalizationsZh extends AppLocalizations { @override String get appSettings_languageUk => '乌克兰'; + @override + String get appSettings_enableMessageTracing => '启用消息追踪'; + + @override + String get appSettings_enableMessageTracingSubtitle => '显示消息的详细路由和时间元数据'; + @override String get appSettings_notifications => '通知'; @@ -2710,22 +2716,22 @@ class AppLocalizationsZh extends AppLocalizations { String get losElevationAttribution => '高程数据:Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => '无线电地平线'; + String get losLegendRadioHorizon => 'Radio horizon'; @override - String get losLegendLosBeam => 'LOS 波束'; + String get losLegendLosBeam => 'LOS beam'; @override - String get losLegendTerrain => '地形'; + String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => '频率'; + String get losFrequencyLabel => 'Frequency'; @override - String get losFrequencyInfoTooltip => '查看计算详情'; + String get losFrequencyInfoTooltip => 'View calculation details'; @override - String get losFrequencyDialogTitle => '无线电地平线计算'; + String get losFrequencyDialogTitle => 'Radio horizon calculation'; @override String losFrequencyDialogDescription( @@ -2734,7 +2740,7 @@ class AppLocalizationsZh extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return '从 k=$baselineK($baselineFreq MHz)开始,计算将 0.15 × (frequency − $baselineFreq) / $baselineFreq,以得到当前 $frequencyMHz MHz 频段的 k approx $kFactor,从而定义弯曲的无线电地平线边界。'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation multiplies 0.15 × (frequency − $baselineFreq) / $baselineFreq to reach k approx $kFactor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 3855e14..2f39fdf 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1557,6 +1557,8 @@ "contacts_floodAdvert": "Overstromingsadvertentie", "contacts_copyAdvertToClipboard": "Advert naar klembord kopiëren", "appSettings_languageRu": "Russisch", + "appSettings_enableMessageTracing": "Berichttracking inschakelen", + "appSettings_enableMessageTracingSubtitle": "Gedetailleerde routerings- en timing-metadata voor berichten weergeven", "contacts_clipboardEmpty": "Knipbord is leeg.", "contacts_addContactFromClipboard": "Contact uit klembord toevoegen", "contacts_contactImported": "Contact is geïmporteerd.", @@ -1716,21 +1718,5 @@ "losPointName": "Puntnaam", "losShowPanelTooltip": "Toon LOS-paneel", "losHidePanelTooltip": "LOS-paneel verbergen", - "losElevationAttribution": "Hoogtegegevens: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Radiohorizon", - "losLegendLosBeam": "LOS-straal", - "losLegendTerrain": "Terrein", - "losFrequencyLabel": "Frequentie", - "losFrequencyInfoTooltip": "Berekeningsdetails bekijken", - "losFrequencyDialogTitle": "Radiohorizon-berekening", - "losFrequencyDialogDescription": "Uitgaande van k={baselineK} bij {baselineFreq} MHz vermenigvuldigt de berekening 0.15 × (frequency − {baselineFreq}) / {baselineFreq} om k approx {kFactor} te bereiken voor de huidige {frequencyMHz}-MHz-band, die de gebogen radiohorizon-limiet definieert.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Hoogtegegevens: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index dde149c..0432f8f 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1552,6 +1552,8 @@ "contacts_chatTraceRoute": "Śledź trasę promienia", "appSettings_languageRu": "Rosyjski", "appSettings_languageUk": "Ukraińska", + "appSettings_enableMessageTracing": "Włącz śledzenie wiadomości", + "appSettings_enableMessageTracingSubtitle": "Pokaż szczegółowe metadane trasowania i czasu dla wiadomości", "contacts_contactImportFailed": "Kontakt nie został zaimportowany.", "contacts_zeroHopAdvert": "Reklama Zero Hop", "contacts_floodAdvert": "Reklama powodziowa", @@ -1716,21 +1718,5 @@ "losPointName": "Nazwa punktu", "losShowPanelTooltip": "Pokaż panel LOS", "losHidePanelTooltip": "Ukryj panel LOS", - "losElevationAttribution": "Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Horyzont radiowy", - "losLegendLosBeam": "Wiązka LOS", - "losLegendTerrain": "Teren", - "losFrequencyLabel": "Częstotliwość", - "losFrequencyInfoTooltip": "Zobacz szczegóły obliczeń", - "losFrequencyDialogTitle": "Obliczanie horyzontu radiowego", - "losFrequencyDialogDescription": "Wychodząc od k={baselineK} przy {baselineFreq} MHz, obliczenie mnoży 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, aby osiągnąć k approx {kFactor} dla bieżącego pasma {frequencyMHz} MHz, które definiuje zakrzywioną granicę horyzontu radiowego.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 7edff74..01c5a83 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1558,6 +1558,8 @@ "contacts_copyAdvertToClipboard": "Copiar Anúncio para Área de Transferência", "contacts_addContactFromClipboard": "Adicionar Contato da Área de Transferência", "appSettings_languageRu": "Russo", + "appSettings_enableMessageTracing": "Ativar rastreamento de mensagens", + "appSettings_enableMessageTracingSubtitle": "Mostrar metadados detalhados de roteamento e tempo para as mensagens", "contacts_ShareContact": "Copiar contato para Área de Transferência", "contacts_contactImportFailed": "Contato falhou ao ser importado.", "contacts_zeroHopContactAdvertSent": "Enviou contato por anúncio.", @@ -1716,21 +1718,5 @@ "losPointName": "Nome do ponto", "losShowPanelTooltip": "Mostrar painel LOS", "losHidePanelTooltip": "Ocultar painel LOS", - "losElevationAttribution": "Dados de elevação: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Horizonte de rádio", - "losLegendLosBeam": "Feixe LOS", - "losLegendTerrain": "Terreno", - "losFrequencyLabel": "Frequência", - "losFrequencyInfoTooltip": "Ver detalhes do cálculo", - "losFrequencyDialogTitle": "Cálculo do horizonte de rádio", - "losFrequencyDialogDescription": "Partindo de k={baselineK} a {baselineFreq} MHz, o cálculo multiplica 0.15 × (frequency − {baselineFreq}) / {baselineFreq} para chegar a k approx {kFactor} para a banda atual de {frequencyMHz} MHz, que define o limite curvo do horizonte de rádio.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Dados de elevação: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 139074b..b8a20d9 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -796,6 +796,8 @@ "contacts_invalidAdvertFormat": "Недействительные контактные данные", "contacts_zeroHopAdvert": "Реклама Zero Hop", "appSettings_languageUk": "Українська", + "appSettings_enableMessageTracing": "Включить трассировку сообщений", + "appSettings_enableMessageTracingSubtitle": "Показывать подробные метаданные о маршрутизации и времени для сообщений", "contacts_floodAdvert": "Рекламный поток", "contacts_clipboardEmpty": "Буфер обмена пуст.", "contacts_copyAdvertToClipboard": "Копировать рекламу в буфер обмена", @@ -956,21 +958,5 @@ "losPointName": "Имя точки", "losShowPanelTooltip": "Показать панель LOS", "losHidePanelTooltip": "Скрыть панель LOS", - "losElevationAttribution": "Данные о высоте: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Радиогоризонт", - "losLegendLosBeam": "Луч LOS", - "losLegendTerrain": "Рельеф", - "losFrequencyLabel": "Частота", - "losFrequencyInfoTooltip": "Просмотреть детали расчёта", - "losFrequencyDialogTitle": "Расчёт радиогоризонта", - "losFrequencyDialogDescription": "Исходя из k={baselineK} при {baselineFreq} MHz, расчёт умножает 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, чтобы получить k approx {kFactor} для текущего диапазона {frequencyMHz} MHz, который определяет изогнутую границу радиогоризонта.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Данные о высоте: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 89a1b0d..3245282 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1558,6 +1558,8 @@ "contacts_copyAdvertToClipboard": "Kopírovať reklamu do schránky", "contacts_invalidAdvertFormat": "Neplatné kontaktné údaje", "appSettings_languageRu": "Ruština", + "appSettings_enableMessageTracing": "Povoliť sledovanie správ", + "appSettings_enableMessageTracingSubtitle": "Zobraziť podrobné metadáta o smerovaní a časovaní správ", "contacts_addContactFromClipboard": "Pridať kontakt z schránky", "contacts_contactImported": "Kontakt bol importovaný.", "contacts_zeroHopContactAdvertSent": "Poslal kontakt cez inzerát.", @@ -1716,21 +1718,5 @@ "losPointName": "Názov bodu", "losShowPanelTooltip": "Zobraziť panel LOS", "losHidePanelTooltip": "Skryť panel LOS", - "losElevationAttribution": "Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Rádiový horizont", - "losLegendLosBeam": "LOS lúč", - "losLegendTerrain": "Terén", - "losFrequencyLabel": "Frekvencia", - "losFrequencyInfoTooltip": "Zobraziť podrobnosti výpočtu", - "losFrequencyDialogTitle": "Výpočet rádiového horizontu", - "losFrequencyDialogDescription": "Vychádzajúc z k={baselineK} pri {baselineFreq} MHz výpočet násobí 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, aby dosiahol k approx {kFactor} pre aktuálne pásmo {frequencyMHz} MHz, ktoré definuje zakrivenú hranicu rádiového horizontu.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 2fe86e0..c560c31 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1552,6 +1552,8 @@ "contacts_pathTraceTo": "Trace route to {name}", "appSettings_languageRu": "Ruščina", "appSettings_languageUk": "Ukrajinsko", + "appSettings_enableMessageTracing": "Omogoči sledenje sporočilom", + "appSettings_enableMessageTracingSubtitle": "Prikaži podrobne metapodatke o usmerjanju in časovnem usklajevanju sporočil", "contacts_contactImported": "Kontakt je bil uvožen.", "contacts_contactImportFailed": "Kontakt ni bil uspešno uvožen.", "contacts_zeroHopAdvert": "Reklama brez posrednikov", @@ -1716,21 +1718,5 @@ "losPointName": "Ime točke", "losShowPanelTooltip": "Pokaži ploščo LOS", "losHidePanelTooltip": "Skrij ploščo LOS", - "losElevationAttribution": "Podatki o višini: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Radijski horizont", - "losLegendLosBeam": "LOS žarek", - "losLegendTerrain": "Teren", - "losFrequencyLabel": "Frekvenca", - "losFrequencyInfoTooltip": "Prikaži podrobnosti izračuna", - "losFrequencyDialogTitle": "Izračun radijskega horizonta", - "losFrequencyDialogDescription": "Izhajajoč iz k={baselineK} pri {baselineFreq} MHz izračun množi 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, da doseže k approx {kFactor} za trenutno {frequencyMHz}-MHz območje, ki določa ukrivljeno mejo radijskega horizonta.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Podatki o višini: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 2625fb2..b93c5ca 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1558,6 +1558,8 @@ "contacts_copyAdvertToClipboard": "Kopiera annons till urklipp", "contacts_invalidAdvertFormat": "Ogiltiga kontaktuppgifter", "appSettings_languageUk": "Ukrainska", + "appSettings_enableMessageTracing": "Aktivera meddelandespårning", + "appSettings_enableMessageTracingSubtitle": "Visa detaljerade metadata om dirigering och tidsinställningar för meddelanden", "contacts_addContactFromClipboard": "Lägg till kontakt från urklipp", "contacts_contactImported": "Kontakt har importerats.", "contacts_zeroHopContactAdvertSent": "Skickat kontakt via annons.", @@ -1716,21 +1718,5 @@ "losPointName": "Punktnamn", "losShowPanelTooltip": "Visa LOS-panelen", "losHidePanelTooltip": "Dölj LOS-panelen", - "losElevationAttribution": "Höjddata: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Radiohorisont", - "losLegendLosBeam": "LOS-stråle", - "losLegendTerrain": "Terräng", - "losFrequencyLabel": "Frekvens", - "losFrequencyInfoTooltip": "Visa beräkningsdetaljer", - "losFrequencyDialogTitle": "Beräkning av radiohorisont", - "losFrequencyDialogDescription": "Med start från k={baselineK} vid {baselineFreq} MHz multiplicerar beräkningen 0.15 × (frequency − {baselineFreq}) / {baselineFreq} för att nå k approx {kFactor} för det aktuella {frequencyMHz}-MHz-bandet, vilket definierar den krökta radiohorisontgränsen.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Höjddata: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 8c28f19..235e4ed 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1559,6 +1559,8 @@ "contacts_copyAdvertToClipboard": "Копіювати оголошення в буфер обміну", "contacts_clipboardEmpty": "Буфер обміну порожній", "appSettings_languageRu": "Російська", + "appSettings_enableMessageTracing": "Увімкнути відстеження повідомлень", + "appSettings_enableMessageTracingSubtitle": "Показувати детальні метадані про маршрутизацію та час для повідомлень", "contacts_ShareContact": "Копіювати контакт у буфер обміну", "contacts_zeroHopContactAdvertFailed": "Не вдалося надіслати контакт.", "contacts_contactAdvertCopied": "Рекламу скопійовано до буфера обміну.", @@ -1716,21 +1718,5 @@ "losPointName": "Назва точки", "losShowPanelTooltip": "Показати панель LOS", "losHidePanelTooltip": "Приховати панель LOS", - "losElevationAttribution": "Дані про висоту: Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "Радіогоризонт", - "losLegendLosBeam": "Промінь LOS", - "losLegendTerrain": "Рельєф", - "losFrequencyLabel": "Частота", - "losFrequencyInfoTooltip": "Переглянути деталі розрахунку", - "losFrequencyDialogTitle": "Розрахунок радіогоризонту", - "losFrequencyDialogDescription": "Виходячи з k={baselineK} при {baselineFreq} MHz, розрахунок множить 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, щоб отримати k approx {kFactor} для поточного діапазону {frequencyMHz} MHz, який визначає вигнуту межу радіогоризонту.", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "Дані про висоту: Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index bd8067f..72f48ad 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -176,6 +176,8 @@ "appSettings_languageBg": "保加利亚", "appSettings_languageRu": "俄语", "appSettings_languageUk": "乌克兰", + "appSettings_enableMessageTracing": "启用消息追踪", + "appSettings_enableMessageTracingSubtitle": "显示消息的详细路由和时间元数据", "appSettings_notifications": "通知", "appSettings_enableNotifications": "启用通知", "appSettings_enableNotificationsSubtitle": "接收消息和广告的通知", @@ -1716,21 +1718,5 @@ "losPointName": "点名称", "losShowPanelTooltip": "显示 LOS 面板", "losHidePanelTooltip": "隐藏 LOS 面板", - "losElevationAttribution": "高程数据:Open-Meteo (CC BY 4.0)", - "losLegendRadioHorizon": "无线电地平线", - "losLegendLosBeam": "LOS 波束", - "losLegendTerrain": "地形", - "losFrequencyLabel": "频率", - "losFrequencyInfoTooltip": "查看计算详情", - "losFrequencyDialogTitle": "无线电地平线计算", - "losFrequencyDialogDescription": "从 k={baselineK}({baselineFreq} MHz)开始,计算将 0.15 × (frequency − {baselineFreq}) / {baselineFreq},以得到当前 {frequencyMHz} MHz 频段的 k approx {kFactor},从而定义弯曲的无线电地平线边界。", - "@losFrequencyDialogDescription": { - "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", - "placeholders": { - "baselineK": { "type": "double" }, - "baselineFreq": { "type": "double" }, - "frequencyMHz": { "type": "double" }, - "kFactor": { "type": "double" } - } - } -} + "losElevationAttribution": "高程数据:Open-Meteo (CC BY 4.0)" +} \ No newline at end of file diff --git a/lib/models/app_settings.dart b/lib/models/app_settings.dart index d9504b3..62ba9ca 100644 --- a/lib/models/app_settings.dart +++ b/lib/models/app_settings.dart @@ -22,6 +22,7 @@ class AppSettings { final bool mapKeyPrefixEnabled; final String mapKeyPrefix; final bool mapShowMarkers; + final bool enableMessageTracing; final Map? mapCacheBounds; final int mapCacheMinZoom; final int mapCacheMaxZoom; @@ -47,6 +48,7 @@ class AppSettings { this.mapKeyPrefixEnabled = false, this.mapKeyPrefix = '', this.mapShowMarkers = true, + this.enableMessageTracing = false, this.mapCacheBounds, this.mapCacheMinZoom = 10, this.mapCacheMaxZoom = 15, @@ -76,6 +78,7 @@ class AppSettings { 'map_key_prefix_enabled': mapKeyPrefixEnabled, 'map_key_prefix': mapKeyPrefix, 'map_show_markers': mapShowMarkers, + 'enable_message_tracing': enableMessageTracing, 'map_cache_bounds': mapCacheBounds, 'map_cache_min_zoom': mapCacheMinZoom, 'map_cache_max_zoom': mapCacheMaxZoom, @@ -112,6 +115,7 @@ class AppSettings { mapKeyPrefixEnabled: json['map_key_prefix_enabled'] as bool? ?? false, mapKeyPrefix: json['map_key_prefix'] as String? ?? '', mapShowMarkers: json['map_show_markers'] as bool? ?? true, + enableMessageTracing: json['enable_message_tracing'] as bool? ?? false, mapCacheBounds: (json['map_cache_bounds'] as Map?)?.map( (key, value) => MapEntry(key.toString(), (value as num).toDouble()), ), @@ -155,6 +159,7 @@ class AppSettings { bool? mapKeyPrefixEnabled, String? mapKeyPrefix, bool? mapShowMarkers, + bool? enableMessageTracing, Object? mapCacheBounds = _unset, int? mapCacheMinZoom, int? mapCacheMaxZoom, @@ -180,6 +185,7 @@ class AppSettings { mapKeyPrefixEnabled: mapKeyPrefixEnabled ?? this.mapKeyPrefixEnabled, mapKeyPrefix: mapKeyPrefix ?? this.mapKeyPrefix, mapShowMarkers: mapShowMarkers ?? this.mapShowMarkers, + enableMessageTracing: enableMessageTracing ?? this.enableMessageTracing, mapCacheBounds: mapCacheBounds == _unset ? this.mapCacheBounds : mapCacheBounds as Map?, diff --git a/lib/screens/app_settings_screen.dart b/lib/screens/app_settings_screen.dart index b309b4d..a2c920e 100644 --- a/lib/screens/app_settings_screen.dart +++ b/lib/screens/app_settings_screen.dart @@ -82,6 +82,18 @@ class AppSettingsScreen extends StatelessWidget { trailing: const Icon(Icons.chevron_right), onTap: () => _showLanguageDialog(context, settingsService), ), + const Divider(height: 1), + SwitchListTile( + secondary: const Icon(Icons.location_searching), + title: Text(context.l10n.appSettings_enableMessageTracing), + subtitle: Text( + context.l10n.appSettings_enableMessageTracingSubtitle, + ), + value: settingsService.settings.enableMessageTracing, + onChanged: (value) { + settingsService.setEnableMessageTracing(value); + }, + ), ], ), ); diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index bf05110..9df91c3 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -17,11 +17,13 @@ import '../helpers/utf8_length_limiter.dart'; import '../l10n/l10n.dart'; import '../models/channel.dart'; import '../models/channel_message.dart'; +import '../services/app_settings_service.dart'; import '../utils/emoji_utils.dart'; import '../widgets/emoji_picker.dart'; import '../widgets/gif_message.dart'; import '../widgets/jump_to_bottom_button.dart'; import '../widgets/gif_picker.dart'; +import '../widgets/message_status_icon.dart'; import 'channel_message_path_screen.dart'; import 'map_screen.dart'; @@ -263,6 +265,8 @@ class _ChannelChatScreenState extends State { } Widget _buildMessageBubble(ChannelMessage message) { + final settingsService = context.watch(); + final enableTracing = settingsService.settings.enableMessageTracing; final isOutgoing = message.isOutgoing; final gifId = _parseGifId(message.text); final poi = _parsePoiMessage(message.text); @@ -334,110 +338,189 @@ class _ChannelChatScreenState extends State { const SizedBox(height: 8), ], if (poi != null) - _buildPoiMessage(context, poi, isOutgoing) + _buildPoiMessage( + context, + poi, + isOutgoing, + trailing: (!enableTracing && isOutgoing) + ? Padding( + padding: const EdgeInsets.only(bottom: 2), + child: MessageStatusIcon( + isAcked: + message.status == + ChannelMessageStatus.sent && + displayPath.isNotEmpty, + isFailed: + message.status == + ChannelMessageStatus.failed, + ), + ) + : null, + ) else if (gifId != null) - ClipRRect( - borderRadius: BorderRadius.circular(8), - child: GifMessage( - url: - 'https://media.giphy.com/media/$gifId/giphy.gif', - backgroundColor: Colors.transparent, - fallbackTextColor: isOutgoing - ? Theme.of(context) - .colorScheme - .onPrimaryContainer - .withValues(alpha: 0.7) - : Theme.of(context).colorScheme.onSurface - .withValues(alpha: 0.6), - ), + Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: GifMessage( + url: + 'https://media.giphy.com/media/$gifId/giphy.gif', + backgroundColor: Colors.transparent, + fallbackTextColor: isOutgoing + ? Theme.of(context) + .colorScheme + .onPrimaryContainer + .withValues(alpha: 0.7) + : Theme.of(context).colorScheme.onSurface + .withValues(alpha: 0.6), + ), + ), + if (!enableTracing && isOutgoing) + Positioned( + top: 0, + right: 0, + child: Container( + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + color: isOutgoing + ? Theme.of( + context, + ).colorScheme.primaryContainer + : Theme.of( + context, + ).colorScheme.surfaceContainerHighest, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(10), + topRight: Radius.circular(8), + ), + ), + child: MessageStatusIcon( + isAcked: + message.status == + ChannelMessageStatus.sent && + displayPath.isNotEmpty, + isFailed: + message.status == + ChannelMessageStatus.failed, + ), + ), + ), + ], ) else - Linkify( - text: message.text, - style: const TextStyle(fontSize: 14), - linkStyle: const TextStyle( - fontSize: 14, - color: Colors.green, - decoration: TextDecoration.underline, - ), - options: const LinkifyOptions( - humanize: false, - defaultToHttps: false, - ), - linkifiers: const [UrlLinkifier()], - onOpen: (link) => - LinkHandler.handleLinkTap(context, link.url), - ), - if (displayPath.isNotEmpty) ...[ - const SizedBox(height: 4), - Padding( - padding: gifId != null - ? const EdgeInsets.symmetric(horizontal: 8) - : EdgeInsets.zero, - child: Text( - 'via ${_formatPathPrefixes(displayPath)}', - style: TextStyle( - fontSize: 11, - color: Colors.grey[600], - ), - ), - ), - ], - const SizedBox(height: 4), - Padding( - padding: gifId != null - ? const EdgeInsets.only( - left: 8, - right: 8, - bottom: 4, - ) - : EdgeInsets.zero, - child: Row( + Row( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - _formatTime(message.timestamp), + Flexible( + child: Linkify( + text: message.text, + style: const TextStyle(fontSize: 14), + linkStyle: const TextStyle( + fontSize: 14, + color: Colors.green, + decoration: TextDecoration.underline, + ), + options: const LinkifyOptions( + humanize: false, + defaultToHttps: false, + ), + linkifiers: const [UrlLinkifier()], + onOpen: (link) => LinkHandler.handleLinkTap( + context, + link.url, + ), + ), + ), + if (!enableTracing && isOutgoing) ...[ + const SizedBox(width: 4), + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: MessageStatusIcon( + isAcked: + message.status == + ChannelMessageStatus.sent && + displayPath.isNotEmpty, + isFailed: + message.status == + ChannelMessageStatus.failed, + ), + ), + ], + ], + ), + if (enableTracing) ...[ + if (displayPath.isNotEmpty) ...[ + const SizedBox(height: 4), + Padding( + padding: gifId != null + ? const EdgeInsets.symmetric(horizontal: 8) + : EdgeInsets.zero, + child: Text( + 'via ${_formatPathPrefixes(displayPath)}', style: TextStyle( fontSize: 11, color: Colors.grey[600], ), ), - if (message.repeatCount > 0) ...[ - const SizedBox(width: 6), - Icon( - Icons.repeat, - size: 12, - color: Colors.grey[600], - ), - const SizedBox(width: 2), + ), + ], + const SizedBox(height: 4), + Padding( + padding: gifId != null + ? const EdgeInsets.only( + left: 8, + right: 8, + bottom: 4, + ) + : EdgeInsets.zero, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ Text( - '${message.repeatCount}', + _formatTime(message.timestamp), style: TextStyle( fontSize: 11, color: Colors.grey[600], ), ), + if (message.repeatCount > 0) ...[ + const SizedBox(width: 6), + Icon( + Icons.repeat, + size: 12, + color: Colors.grey[600], + ), + const SizedBox(width: 2), + Text( + '${message.repeatCount}', + style: TextStyle( + fontSize: 11, + color: Colors.grey[600], + ), + ), + ], + if (isOutgoing) ...[ + const SizedBox(width: 4), + Icon( + message.status == ChannelMessageStatus.sent + ? Icons.check + : message.status == + ChannelMessageStatus.pending + ? Icons.schedule + : Icons.error_outline, + size: 14, + color: + message.status == + ChannelMessageStatus.failed + ? Colors.red + : Colors.grey[600], + ), + ], ], - if (isOutgoing) ...[ - const SizedBox(width: 4), - Icon( - message.status == ChannelMessageStatus.sent - ? Icons.check - : message.status == - ChannelMessageStatus.pending - ? Icons.schedule - : Icons.error_outline, - size: 14, - color: - message.status == - ChannelMessageStatus.failed - ? Colors.red - : Colors.grey[600], - ), - ], - ], + ), ), - ), + ], ], ), ), @@ -650,7 +733,12 @@ class _ChannelChatScreenState extends State { return _PoiInfo(lat: lat, lon: lon, label: label); } - Widget _buildPoiMessage(BuildContext context, _PoiInfo poi, bool isOutgoing) { + Widget _buildPoiMessage( + BuildContext context, + _PoiInfo poi, + bool isOutgoing, { + Widget? trailing, + }) { final colorScheme = Theme.of(context).colorScheme; final textColor = isOutgoing ? colorScheme.onPrimaryContainer @@ -696,6 +784,7 @@ class _ChannelChatScreenState extends State { ], ), ), + if (trailing != null) ...[const SizedBox(width: 4), trailing], ], ); } diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index ad897a0..3556d6d 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -13,6 +13,7 @@ import 'package:latlong2/latlong.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; import '../helpers/reaction_helper.dart'; +import '../widgets/message_status_icon.dart'; import '../helpers/chat_scroll_controller.dart'; import '../helpers/link_handler.dart'; import '../helpers/utf8_length_limiter.dart'; @@ -20,6 +21,7 @@ import '../models/channel_message.dart'; import '../models/contact.dart'; import '../models/message.dart'; import '../models/path_history.dart'; +import '../services/app_settings_service.dart'; import '../services/path_history_service.dart'; import '../widgets/elements_ui.dart'; import 'channel_message_path_screen.dart'; @@ -1172,6 +1174,8 @@ class _MessageBubble extends StatelessWidget { @override Widget build(BuildContext context) { + final settingsService = context.watch(); + final enableTracing = settingsService.settings.enableMessageTracing; final isOutgoing = message.isOutgoing; final colorScheme = Theme.of(context).colorScheme; final gifId = _parseGifId(message.text); @@ -1249,102 +1253,175 @@ class _MessageBubble extends StatelessWidget { if (gifId == null) const SizedBox(height: 4), ], if (poi != null) - _buildPoiMessage(context, poi, textColor, metaColor) + _buildPoiMessage( + context, + poi, + textColor, + metaColor, + trailing: (!enableTracing && isOutgoing) + ? Padding( + padding: const EdgeInsets.only(bottom: 2), + child: MessageStatusIcon( + isAcked: + message.status == + MessageStatus.delivered && + message.pathBytes.isNotEmpty, + isFailed: + message.status == + MessageStatus.failed, + ), + ) + : null, + ) else if (gifId != null) - ClipRRect( - borderRadius: BorderRadius.circular(12), - child: GifMessage( - url: - 'https://media.giphy.com/media/$gifId/giphy.gif', - backgroundColor: Colors.transparent, - fallbackTextColor: textColor.withValues( - alpha: 0.7, + Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: GifMessage( + url: + 'https://media.giphy.com/media/$gifId/giphy.gif', + backgroundColor: Colors.transparent, + fallbackTextColor: textColor.withValues( + alpha: 0.7, + ), + ), ), - ), + if (!enableTracing && isOutgoing) + Positioned( + top: 0, + right: 0, + child: Container( + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + color: bubbleColor, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(10), + topRight: Radius.circular(12), + ), + ), + child: MessageStatusIcon( + isAcked: + message.status == + MessageStatus.delivered && + message.pathBytes.isNotEmpty, + isFailed: + message.status == + MessageStatus.failed, + ), + ), + ), + ], ) else - Linkify( - text: messageText, - style: TextStyle(color: textColor), - linkStyle: const TextStyle( - color: Colors.green, - decoration: TextDecoration.underline, - ), - options: const LinkifyOptions( - humanize: false, - defaultToHttps: false, - ), - linkifiers: const [UrlLinkifier()], - onOpen: (link) => - LinkHandler.handleLinkTap(context, link.url), - ), - if (isOutgoing && message.retryCount > 0) ...[ - const SizedBox(height: 4), - Padding( - padding: gifId != null - ? const EdgeInsets.symmetric(horizontal: 8) - : EdgeInsets.zero, - child: Text( - context.l10n.chat_retryCount( - message.retryCount, - 4, - ), - style: TextStyle( - fontSize: 10, - color: metaColor, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - const SizedBox(height: 4), - Padding( - padding: gifId != null - ? const EdgeInsets.only( - left: 8, - right: 8, - bottom: 4, - ) - : EdgeInsets.zero, - child: Wrap( - spacing: 4, - crossAxisAlignment: WrapCrossAlignment.center, + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - _formatTime(message.timestamp), - style: TextStyle( - fontSize: 10, - color: metaColor, + Flexible( + child: Linkify( + text: messageText, + style: TextStyle(color: textColor), + linkStyle: const TextStyle( + color: Colors.green, + decoration: TextDecoration.underline, + ), + options: const LinkifyOptions( + humanize: false, + defaultToHttps: false, + ), + linkifiers: const [UrlLinkifier()], + onOpen: (link) => LinkHandler.handleLinkTap( + context, + link.url, + ), ), ), - if (isOutgoing) ...[ + if (!enableTracing && isOutgoing) ...[ const SizedBox(width: 4), - _buildStatusIcon(metaColor), - ], - if (message.tripTimeMs != null && - message.status == - MessageStatus.delivered) ...[ - const SizedBox(width: 4), - Icon( - Icons.speed, - size: 10, - color: isOutgoing - ? metaColor - : Colors.green[700], - ), - Text( - '${(message.tripTimeMs! / 1000).toStringAsFixed(1)}s', - style: TextStyle( - fontSize: 9, - color: isOutgoing - ? metaColor - : Colors.green[700], + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: MessageStatusIcon( + isAcked: + message.status == + MessageStatus.delivered && + message.pathBytes.isNotEmpty, + isFailed: + message.status == MessageStatus.failed, ), ), ], ], ), - ), + if (enableTracing) ...[ + if (isOutgoing && message.retryCount > 0) ...[ + const SizedBox(height: 4), + Padding( + padding: gifId != null + ? const EdgeInsets.symmetric(horizontal: 8) + : EdgeInsets.zero, + child: Text( + context.l10n.chat_retryCount( + message.retryCount, + 4, + ), + style: TextStyle( + fontSize: 10, + color: metaColor, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + const SizedBox(height: 4), + Padding( + padding: gifId != null + ? const EdgeInsets.only( + left: 8, + right: 8, + bottom: 4, + ) + : EdgeInsets.zero, + child: Wrap( + spacing: 4, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + _formatTime(message.timestamp), + style: TextStyle( + fontSize: 10, + color: metaColor, + ), + ), + if (isOutgoing) ...[ + const SizedBox(width: 4), + _buildStatusIcon(metaColor), + ], + if (message.tripTimeMs != null && + message.status == + MessageStatus.delivered) ...[ + const SizedBox(width: 4), + Icon( + Icons.speed, + size: 10, + color: isOutgoing + ? metaColor + : Colors.green[700], + ), + Text( + '${(message.tripTimeMs! / 1000).toStringAsFixed(1)}s', + style: TextStyle( + fontSize: 9, + color: isOutgoing + ? metaColor + : Colors.green[700], + ), + ), + ], + ], + ), + ), + ], ], ), ), @@ -1387,8 +1464,9 @@ class _MessageBubble extends StatelessWidget { BuildContext context, _PoiInfo poi, Color textColor, - Color metaColor, - ) { + Color metaColor, { + Widget? trailing, + }) { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -1425,6 +1503,7 @@ class _MessageBubble extends StatelessWidget { ], ), ), + if (trailing != null) ...[const SizedBox(width: 4), trailing], ], ); } diff --git a/lib/services/app_settings_service.dart b/lib/services/app_settings_service.dart index e80f903..eacf26f 100644 --- a/lib/services/app_settings_service.dart +++ b/lib/services/app_settings_service.dart @@ -80,6 +80,10 @@ class AppSettingsService extends ChangeNotifier { await updateSettings(_settings.copyWith(mapShowMarkers: value)); } + Future setEnableMessageTracing(bool value) async { + await updateSettings(_settings.copyWith(enableMessageTracing: value)); + } + Future setMapCacheBounds(Map? value) async { await updateSettings(_settings.copyWith(mapCacheBounds: value)); } diff --git a/lib/widgets/message_status_icon.dart b/lib/widgets/message_status_icon.dart new file mode 100644 index 0000000..0689f0b --- /dev/null +++ b/lib/widgets/message_status_icon.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class MessageStatusIcon extends StatelessWidget { + final bool isAcked; + final bool isFailed; + final double size; + + const MessageStatusIcon({ + super.key, + required this.isAcked, + this.isFailed = false, + this.size = 14, + }); + + @override + Widget build(BuildContext context) { + if (isFailed) { + return Icon(Icons.cancel, size: size, color: Colors.red); + } + + final Color color; + if (isAcked) { + color = Colors.green; + } else { + color = Colors.grey; + } + + return SvgPicture.asset( + 'assets/icons/done_all.svg', + width: size, + height: size, + colorFilter: ColorFilter.mode(color, BlendMode.srcIn), + ); + } +} diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 65fed26..8224cfb 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -5,10 +5,13 @@ PODS: - flutter_local_notifications (0.0.1): - FlutterMacOS - FlutterMacOS (1.0.0) - - mobile_scanner (6.0.2): + - mobile_scanner (7.0.0): + - Flutter - FlutterMacOS - package_info_plus (0.0.1): - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -24,8 +27,9 @@ DEPENDENCIES: - flutter_blue_plus_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`) + - mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) @@ -39,9 +43,11 @@ EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral mobile_scanner: - :path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos + :path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin package_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite_darwin: @@ -53,10 +59,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3 - flutter_local_notifications: 13862b132e32eb858dea558a86d45d08daeacfe7 + flutter_local_notifications: 4bf37a31afde695b56091b4ae3e4d9c7a7e6cda0 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - mobile_scanner: 0e365ed56cad24f28c0fd858ca04edefb40dfac3 + mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd diff --git a/pubspec.yaml b/pubspec.yaml index 3624b93..54aab31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,8 @@ dependencies: gpx: ^2.3.0 path_provider: ^2.1.5 share_plus: ^12.0.1 + web: ^1.1.1 + flutter_svg: ^2.0.10+1 dev_dependencies: flutter_test: @@ -87,6 +89,7 @@ flutter: assets: - assets/images/ + - assets/icons/ flutter_launcher_icons: android: true diff --git a/untranslated.json b/untranslated.json index 9e26dfe..f9183cb 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1 +1,141 @@ -{} \ No newline at end of file +{ + "bg": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "de": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "es": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "fr": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "it": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "nl": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "pl": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "pt": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "ru": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "sk": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "sl": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "sv": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "uk": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ], + + "zh": [ + "losLegendRadioHorizon", + "losLegendLosBeam", + "losLegendTerrain", + "losFrequencyLabel", + "losFrequencyInfoTooltip", + "losFrequencyDialogTitle", + "losFrequencyDialogDescription" + ] +}