From c09af98bef3c57875d88faf33c943b8257364b32 Mon Sep 17 00:00:00 2001 From: "Enot (ded) Skelly" Date: Tue, 5 May 2026 12:41:06 -0700 Subject: [PATCH 1/2] basic repeater chan util just repeater stats for now total channel utilization over uptime i.e. util = (rxsecs+txsecs) / upsecs --- lib/l10n/app_en.arb | 1 + lib/l10n/app_localizations.dart | 6 +++ lib/l10n/app_localizations_bg.dart | 3 ++ lib/l10n/app_localizations_de.dart | 3 ++ lib/l10n/app_localizations_en.dart | 3 ++ lib/l10n/app_localizations_es.dart | 3 ++ lib/l10n/app_localizations_fr.dart | 3 ++ lib/l10n/app_localizations_hu.dart | 3 ++ lib/l10n/app_localizations_it.dart | 3 ++ lib/l10n/app_localizations_ja.dart | 3 ++ lib/l10n/app_localizations_ko.dart | 3 ++ lib/l10n/app_localizations_nl.dart | 3 ++ lib/l10n/app_localizations_pl.dart | 3 ++ lib/l10n/app_localizations_pt.dart | 3 ++ lib/l10n/app_localizations_ru.dart | 3 ++ lib/l10n/app_localizations_sk.dart | 3 ++ lib/l10n/app_localizations_sl.dart | 3 ++ lib/l10n/app_localizations_sv.dart | 3 ++ lib/l10n/app_localizations_uk.dart | 3 ++ lib/l10n/app_localizations_zh.dart | 3 ++ lib/screens/repeater_status_screen.dart | 14 +++++++ linux/flutter/generated_plugins.cmake | 1 + untranslated.json | 51 ++++++++++++++++--------- windows/flutter/generated_plugins.cmake | 1 + 24 files changed, 111 insertions(+), 17 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 36a98c6d..28b29cc6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1168,6 +1168,7 @@ "repeater_noiseFloor": "Noise Floor", "repeater_txAirtime": "TX Airtime", "repeater_rxAirtime": "RX Airtime", + "repeater_chanUtil": "Channel Utilization", "repeater_packetStatistics": "Packet Statistics", "repeater_sent": "Sent", "repeater_received": "Received", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index c5720915..ef50b264 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -3909,6 +3909,12 @@ abstract class AppLocalizations { /// **'RX Airtime'** String get repeater_rxAirtime; + /// No description provided for @repeater_chanUtil. + /// + /// In en, this message translates to: + /// **'Channel Utilization'** + String get repeater_chanUtil; + /// No description provided for @repeater_packetStatistics. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 46df9bab..21cadcb7 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2180,6 +2180,9 @@ class AppLocalizationsBg extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Статистика на пакетите'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f6e264d3..d35a6de9 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2176,6 +2176,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Paketstatistiken'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 3391d333..88eb15fb 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2135,6 +2135,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Packet Statistics'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 6314934e..6709298e 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2172,6 +2172,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Estadísticas del Paquete'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index d5f014c7..e4fba305 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2186,6 +2186,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Statistiques des paquets'; diff --git a/lib/l10n/app_localizations_hu.dart b/lib/l10n/app_localizations_hu.dart index b0777599..c5ad2a86 100644 --- a/lib/l10n/app_localizations_hu.dart +++ b/lib/l10n/app_localizations_hu.dart @@ -2189,6 +2189,9 @@ class AppLocalizationsHu extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Csomagok statisztikája'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 67a10de4..c7996a36 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2175,6 +2175,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Statistiche del Pacchetto'; diff --git a/lib/l10n/app_localizations_ja.dart b/lib/l10n/app_localizations_ja.dart index 29b556c6..66980462 100644 --- a/lib/l10n/app_localizations_ja.dart +++ b/lib/l10n/app_localizations_ja.dart @@ -2086,6 +2086,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get repeater_rxAirtime => 'RX 空き時間'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'パケット統計'; diff --git a/lib/l10n/app_localizations_ko.dart b/lib/l10n/app_localizations_ko.dart index 4b016d36..23a20ec7 100644 --- a/lib/l10n/app_localizations_ko.dart +++ b/lib/l10n/app_localizations_ko.dart @@ -2083,6 +2083,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get repeater_rxAirtime => 'RX 에어타임'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => '패킷 통계'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 4db1cced..7064eaf5 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2161,6 +2161,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get repeater_rxAirtime => 'RX-zendtijd'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Pakketstatistieken'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 3f19da09..40b654a4 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2190,6 +2190,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get repeater_rxAirtime => 'Czas odbioru RX'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Statystyki pakietów'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 523ba2e7..c71964c7 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2172,6 +2172,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Estatísticas de Pacote'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index a90cd77f..f88e0288 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2177,6 +2177,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get repeater_rxAirtime => 'Время эфира (приём)'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Статистика пакетов'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index e7711be5..6ea8d584 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2162,6 +2162,9 @@ class AppLocalizationsSk extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Statistiky balíka'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 8a16ae02..c681906b 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2159,6 +2159,9 @@ class AppLocalizationsSl extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Statistika paketa'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 754058c6..cfb2eb6e 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2148,6 +2148,9 @@ class AppLocalizationsSv extends AppLocalizations { @override String get repeater_rxAirtime => 'RX Airtime'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Paketstatistik'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index d565747a..9d978b87 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2173,6 +2173,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get repeater_rxAirtime => 'Ефірний час RX'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => 'Статистика пакетів'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 54da237a..628583b2 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2043,6 +2043,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get repeater_rxAirtime => '接收空中时间'; + @override + String get repeater_chanUtil => 'Channel Utilization'; + @override String get repeater_packetStatistics => '数据包统计'; diff --git a/lib/screens/repeater_status_screen.dart b/lib/screens/repeater_status_screen.dart index 720c32a8..66dc46b0 100644 --- a/lib/screens/repeater_status_screen.dart +++ b/lib/screens/repeater_status_screen.dart @@ -56,6 +56,7 @@ class _RepeaterStatusScreenState extends State { int? _directRx; int? _dupFlood; int? _dupDirect; + double? _chanUtil; PathSelection? _pendingStatusSelection; @override @@ -192,6 +193,7 @@ class _RepeaterStatusScreenState extends State { _lastSnr = lastSnrRaw / 4.0; _dupDirect = directDups; _dupFlood = floodDups; + _chanUtil = ((txAirSecs + rxAirSecs) / uptimeSecs) * 100; }); final connector = Provider.of(context, listen: false); connector.updateRepeaterBatterySnapshot( @@ -283,6 +285,7 @@ class _RepeaterStatusScreenState extends State { _directRx = null; _dupFlood = null; _dupDirect = null; + _chanUtil = null; }); try { @@ -570,6 +573,7 @@ class _RepeaterStatusScreenState extends State { _buildInfoRow(l10n.repeater_sent, _packetTxText()), _buildInfoRow(l10n.repeater_received, _packetRxText()), _buildInfoRow(l10n.repeater_duplicates, _duplicateText()), + _buildInfoRow(l10n.repeater_chanUtil, _chanUtilText()), ], ), ), @@ -673,6 +677,11 @@ class _RepeaterStatusScreenState extends State { return l10n.repeater_packetRxTotal(_packetsRecv!, flood, direct); } + String _chanUtilText() { + if (_chanUtil == null) return '—'; + return _formatPercent(_chanUtil); + } + String _duplicateText() { final l10n = context.l10n; if (_dupFlood != null || _dupDirect != null) { @@ -693,6 +702,11 @@ class _RepeaterStatusScreenState extends State { return suffix == null ? value.toString() : '$value$suffix'; } + String _formatPercent(double? p) { + if (p == null) return '—'; + return '${p.toStringAsFixed(2)}%'; + } + String _formatSnr(double? snr) { if (snr == null) return '—'; return snr.toStringAsFixed(2); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 379e36fa..93e46829 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/untranslated.json b/untranslated.json index ec563845..5a4646bf 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,86 +1,103 @@ { "bg": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "de": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "es": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "fr": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "hu": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "it": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "ja": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "ko": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "nl": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "pl": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "pt": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "ru": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "sk": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "sl": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "sv": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "uk": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ], "zh": [ "chat_markAsUnread", - "chat_newMessages" + "chat_newMessages", + "repeater_chanUtil" ] } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f02857f4..533a1712 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial flutter_local_notifications_windows + jni ) set(PLUGIN_BUNDLED_LIBRARIES) From bc5b12f1efbbf72400eb28ef5dfd3499dcf866e2 Mon Sep 17 00:00:00 2001 From: "Enot (ded) Skelly" Date: Tue, 5 May 2026 12:46:01 -0700 Subject: [PATCH 2/2] formattting not mine still --- lib/services/translation_service.dart | 40 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/services/translation_service.dart b/lib/services/translation_service.dart index 46cf7ea8..294a7848 100644 --- a/lib/services/translation_service.dart +++ b/lib/services/translation_service.dart @@ -537,27 +537,39 @@ class TranslationService extends ChangeNotifier { final lower = trimmed.toLowerCase(); final patterns = { 'uk': r'\b(привіт|дякую|будь|ласка|як|де|не|так|це|є|най|ще|може|для)\b', - 'ru': r'\b(что|это|как|не|да|нет|он|она|они|быть|есть|для|сегодня|если|уже|может)\b', + 'ru': + r'\b(что|это|как|не|да|нет|он|она|они|быть|есть|для|сегодня|если|уже|может)\b', 'bg': r'\b(ще|няма|благодаря|моля|това|какво|тук|ние|вие|не|със|за)\b', - 'de': r'\b(der|die|das|und|ist|nicht|ein|eine|ich|für|mit|auf|zu|auch|als|an|im|am|es|dem|den|sich|von)\b', - 'en': r'\b(the|and|is|you|for|with|from|not|that|this|have|be|are|was|were|but|can|will|your|what|when|how|they)\b', - 'es': r'\b(el|la|los|las|es|que|de|en|con|por|para|no|un|una|se|como|su|al|del|está)\b', - 'fr': r'\b(le|la|les|un|une|et|est|que|qui|pour|dans|pas|avec|sur|ne|vous|il|elle|des|ce|cette|je|tu|nous|vous)\b', - 'it': r'\b(il|la|lo|un|una|che|di|da|in|per|con|non|si|mi|ti|noi|voi|lui|lei)\b', - 'pt': r'\b(os|as|que|de|do|da|em|para|com|por|não|uma|um|se|você|também)\b', - 'nl': r'\b(de|het|een|en|is|niet|dat|wat|je|ik|op|aan|voor|met|als|nog|zijn)\b', - 'sv': r'\b(och|är|det|att|som|en|på|inte|har|var|men|du|jag|vi|ni|den|detta)\b', - 'pl': r'\b(na|się|nie|jest|to|że|do|od|dla|czy|tak|ale|ma|jak|on|ona|my)\b', + 'de': + r'\b(der|die|das|und|ist|nicht|ein|eine|ich|für|mit|auf|zu|auch|als|an|im|am|es|dem|den|sich|von)\b', + 'en': + r'\b(the|and|is|you|for|with|from|not|that|this|have|be|are|was|were|but|can|will|your|what|when|how|they)\b', + 'es': + r'\b(el|la|los|las|es|que|de|en|con|por|para|no|un|una|se|como|su|al|del|está)\b', + 'fr': + r'\b(le|la|les|un|une|et|est|que|qui|pour|dans|pas|avec|sur|ne|vous|il|elle|des|ce|cette|je|tu|nous|vous)\b', + 'it': + r'\b(il|la|lo|un|una|che|di|da|in|per|con|non|si|mi|ti|noi|voi|lui|lei)\b', + 'pt': + r'\b(os|as|que|de|do|da|em|para|com|por|não|uma|um|se|você|também)\b', + 'nl': + r'\b(de|het|een|en|is|niet|dat|wat|je|ik|op|aan|voor|met|als|nog|zijn)\b', + 'sv': + r'\b(och|är|det|att|som|en|på|inte|har|var|men|du|jag|vi|ni|den|detta)\b', + 'pl': + r'\b(na|się|nie|jest|to|że|do|od|dla|czy|tak|ale|ma|jak|on|ona|my)\b', 'sk': r'\b(je|na|so|že|do|od|za|si|to|ten|tá|tí|ako|má|nie|som|sa)\b', 'sl': r'\b(in|je|na|se|da|za|od|ne|to|ta|so|kako|bo|sem|si)\b', - 'hu': r'\b(az|és|nem|van|volt|hogy|mit|mire|ki|mi|ez|azért|is|de|ha|te|ő|mi|itt)\b', + 'hu': + r'\b(az|és|nem|van|volt|hogy|mit|mire|ki|mi|ez|azért|is|de|ha|te|ő|mi|itt)\b', }; final scores = {}; for (final entry in patterns.entries) { - scores[entry.key] = RegExp(entry.value, caseSensitive: false) - .allMatches(lower) - .length; + scores[entry.key] = RegExp( + entry.value, + caseSensitive: false, + ).allMatches(lower).length; } final sorted = scores.entries.toList()