From ba2763a3f61109f19e80a46f4760805b01128532 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Fri, 20 Feb 2026 01:28:13 -0500 Subject: [PATCH 01/34] fix(channels): make edit/delete actions use parent context after bottom sheet closes Root cause: edit/delete dialogs were opened from the sheet context after Navigator.pop, so context.mounted was false and follow-up actions never ran. Also keeps async await/error handling for channel edit/delete so failures surface to users instead of silently dropping. --- lib/screens/channels_screen.dart | 70 +++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index 6b8b92d..30c52f1 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -478,9 +478,10 @@ class _ChannelsScreenState extends State MeshCoreConnector connector, Channel channel, ) { + final parentContext = context; showModalBottomSheet( - context: context, - builder: (context) => SafeArea( + context: parentContext, + builder: (sheetContext) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -488,10 +489,10 @@ class _ChannelsScreenState extends State leading: const Icon(Icons.edit_outlined), title: Text(context.l10n.channels_editChannel), onTap: () async { - Navigator.pop(context); + Navigator.pop(sheetContext); await Future.delayed(const Duration(milliseconds: 100)); - if (context.mounted) { - _showEditChannelDialog(context, connector, channel); + if (parentContext.mounted) { + _showEditChannelDialog(parentContext, connector, channel); } }, ), @@ -502,10 +503,10 @@ class _ChannelsScreenState extends State style: const TextStyle(color: Colors.red), ), onTap: () async { - Navigator.pop(context); + Navigator.pop(sheetContext); await Future.delayed(const Duration(milliseconds: 100)); - if (context.mounted) { - _confirmDeleteChannel(context, connector, channel); + if (parentContext.mounted) { + _confirmDeleteChannel(parentContext, connector, channel); } }, ), @@ -1415,7 +1416,7 @@ class _ChannelsScreenState extends State child: Text(dialogContext.l10n.common_cancel), ), FilledButton( - onPressed: () { + onPressed: () async { final name = nameController.text.trim(); final pskHex = pskController.text.trim(); @@ -1432,13 +1433,25 @@ class _ChannelsScreenState extends State } Navigator.pop(dialogContext); - connector.setChannel(channel.index, name, psk); - connector.setChannelSmazEnabled(channel.index, smazEnabled); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.channels_channelUpdated(name)), - ), - ); + try { + await connector.setChannel(channel.index, name, psk); + await connector.setChannelSmazEnabled( + channel.index, + smazEnabled, + ); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(context.l10n.channels_channelUpdated(name)), + ), + ); + } catch (e, st) { + debugPrint(st.toString()); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Failed to update channel: $e')), + ); + } }, child: Text(dialogContext.l10n.common_save), ), @@ -1466,16 +1479,25 @@ class _ChannelsScreenState extends State child: Text(dialogContext.l10n.common_cancel), ), TextButton( - onPressed: () { + onPressed: () async { Navigator.pop(dialogContext); - connector.deleteChannel(channel.index); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - context.l10n.channels_channelDeleted(channel.name), + try { + await connector.deleteChannel(channel.index); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + context.l10n.channels_channelDeleted(channel.name), + ), ), - ), - ); + ); + } catch (e, st) { + debugPrint(st.toString()); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Failed to delete channel: $e')), + ); + } }, child: Text( dialogContext.l10n.common_delete, From 332bb5ef3afcb64eef89ceccf143ac5ac2570391 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:06:08 -0500 Subject: [PATCH 02/34] Updated PR and Added snackbar Translations --- .local-agent/AGENTS.local.md | 48 +++++++++++++++++++++++++ .local-agent/memory.local.md | 6 ++++ lib/l10n/app_en.arb | 8 +++++ lib/l10n/app_localizations.dart | 6 ++++ lib/l10n/app_localizations_bg.dart | 5 +++ lib/l10n/app_localizations_de.dart | 5 +++ lib/l10n/app_localizations_en.dart | 5 +++ lib/l10n/app_localizations_es.dart | 5 +++ lib/l10n/app_localizations_fr.dart | 5 +++ lib/l10n/app_localizations_it.dart | 5 +++ lib/l10n/app_localizations_nl.dart | 5 +++ lib/l10n/app_localizations_pl.dart | 5 +++ lib/l10n/app_localizations_pt.dart | 5 +++ lib/l10n/app_localizations_ru.dart | 5 +++ lib/l10n/app_localizations_sk.dart | 5 +++ lib/l10n/app_localizations_sl.dart | 5 +++ lib/l10n/app_localizations_sv.dart | 5 +++ lib/l10n/app_localizations_uk.dart | 5 +++ lib/l10n/app_localizations_zh.dart | 5 +++ lib/screens/channels_screen.dart | 16 +++------ untranslated.json | 58 +++++++++++++++++++++++++++++- 21 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 .local-agent/AGENTS.local.md create mode 100644 .local-agent/memory.local.md diff --git a/.local-agent/AGENTS.local.md b/.local-agent/AGENTS.local.md new file mode 100644 index 0000000..2c61ef8 --- /dev/null +++ b/.local-agent/AGENTS.local.md @@ -0,0 +1,48 @@ +# Local Agent Operating Rules (Untracked) + +This file is NOT version-controlled. +It overrides default agent behavior for this workstation only. + +--- + +## Core Behavior + +- Always search the codebase before editing. +- Produce a short plan before modifying BLE or protocol logic. +- Never modify BLE frame structure or command codes without explicit approval. +- After editing connector code, re-check command/response mappings. +- Never perform destructive operations (delete files, mass refactor) without confirmation. + +--- + +## Protocol Discipline + +- maxFrameSize must remain 172 unless explicitly instructed. +- Identity hash size is 1 byte (PATH_HASH_SIZE). +- Companion radio formats must not change silently. +- Command codes and response codes must remain backward-compatible. + +--- + +## Coding Discipline + +- Keep modifications minimal. +- Prefer refactoring over rewriting. +- Follow existing Flutter patterns (StatelessWidget + Consumer). +- Avoid premature abstraction. +- Explain what changed and why. + +--- + +## Learning Mode + +When discovering: +- a working build command +- a protocol quirk +- a confirmed packet layout rule + +Append a concise bullet to: + +.local-agent/memory.local.md + +Keep memory under 15 bullets max. diff --git a/.local-agent/memory.local.md b/.local-agent/memory.local.md new file mode 100644 index 0000000..a714fbc --- /dev/null +++ b/.local-agent/memory.local.md @@ -0,0 +1,6 @@ +\# Local Learned Patterns (Machine-Specific) + +(empty) + + + diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 67ca72e..6af00bc 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -363,6 +363,14 @@ } } }, + "channels_channelDeleteFailed": "Failed to delete channel \"{name}\"", + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "channels_channelDeleted": "Channel \"{name}\" deleted", "@channels_channelDeleted": { "placeholders": { diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index e9686ce..8030843 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1570,6 +1570,12 @@ abstract class AppLocalizations { /// **'Delete \"{name}\"? This cannot be undone.'** String channels_deleteChannelConfirm(String name); + /// No description provided for @channels_channelDeleteFailed. + /// + /// In en, this message translates to: + /// **'Failed to delete channel \"{name}\"'** + String channels_channelDeleteFailed(String name); + /// No description provided for @channels_channelDeleted. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index cf4bf7b..25b0631 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -812,6 +812,11 @@ class AppLocalizationsBg extends AppLocalizations { return 'Изтрий \"$name\"? Това не може да бъде отменено.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Каналът \"$name\" е изтрит'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index c6a07a4..9ba8409 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -809,6 +809,11 @@ class AppLocalizationsDe extends AppLocalizations { return 'Löschen von \"$name\"? Dies kann nicht rückgängig gemacht werden.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanal \"$name\" gelöscht'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 254b5f4..146edb8 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -801,6 +801,11 @@ class AppLocalizationsEn extends AppLocalizations { return 'Delete \"$name\"? This cannot be undone.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Channel \"$name\" deleted'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index dcde365..6c9a517 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -810,6 +810,11 @@ class AppLocalizationsEs extends AppLocalizations { return 'Eliminar \"$name\"? Esto no se puede deshacer.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Canal \"$name\" eliminado'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index c4e1e27..3b99772 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -812,6 +812,11 @@ class AppLocalizationsFr extends AppLocalizations { return 'Supprimer $name? Cela ne peut pas être annulé.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Le canal \"$name\" a été supprimé'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index d8e27f8..7447fad 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -808,6 +808,11 @@ class AppLocalizationsIt extends AppLocalizations { return 'Eliminare \"$name\"? Non può essere annullato.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Canale \"$name\" eliminato'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 0a50e8b..6e4a2af 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -806,6 +806,11 @@ class AppLocalizationsNl extends AppLocalizations { return 'Verwijderen \"$name\"? Dit kan niet worden teruggedraaid.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanaal \"$name\" verwijderd'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 31dd8b5..dee97c0 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -811,6 +811,11 @@ class AppLocalizationsPl extends AppLocalizations { return 'Usuń \"$name\"? Nie można tego cofnąć.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanał \"$name\" usunięto'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 5092826..22c5a2e 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -811,6 +811,11 @@ class AppLocalizationsPt extends AppLocalizations { return 'Excluir \"$name\"? Não pode ser desfeito.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Canal \"$name\" excluído'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 570b7c8..5afbd87 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -809,6 +809,11 @@ class AppLocalizationsRu extends AppLocalizations { return 'Удалить \"$name\"? Это действие нельзя отменить.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Канал \"$name\" удалён'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 8bbb6de..44f5cbf 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -806,6 +806,11 @@ class AppLocalizationsSk extends AppLocalizations { return 'Odstrániť \"$name\"? To sa nedá zrušiť.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanál \"$name\" bol odstránený'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 61e3058..455d5aa 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -804,6 +804,11 @@ class AppLocalizationsSl extends AppLocalizations { return 'Izbrišem \"$name\"? To se ne da povrniti.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanal \"$name\" izbrisan.'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 79b30b8..6f94870 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -800,6 +800,11 @@ class AppLocalizationsSv extends AppLocalizations { return 'Radera \"$name\"? Detta kan inte ångras.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Kanalen \"$name\" raderad'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index f367002..1d6cf23 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -807,6 +807,11 @@ class AppLocalizationsUk extends AppLocalizations { return 'Видалити $name? Це не можна скасувати.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return 'Канал «$name» видалено'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 7641800..b297297 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -769,6 +769,11 @@ class AppLocalizationsZh extends AppLocalizations { return 'Delete \"$name\"? This cannot be undone.'; } + @override + String channels_channelDeleteFailed(String name) { + return 'Failed to delete channel \"$name\"'; + } + @override String channels_channelDeleted(String name) { return '删除频道 \"$name\"'; diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index 892ac63..d2a2e3d 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -1524,18 +1524,14 @@ class _ChannelsScreenState extends State try { await connector.deleteChannel(channel.index); - channelMessageStore.clearChannelMessages( - channel.index, - ); + channelMessageStore.clearChannelMessages(channel.index); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - context.l10n.channels_channelDeleted( - channel.name, - ), + context.l10n.channels_channelDeleted(channel.name), ), ), ); @@ -1545,17 +1541,13 @@ class _ChannelsScreenState extends State ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - context.l10n.channels_channelDeleteFailed( - channel.name, - ), + context.l10n.channels_channelDeleteFailed(channel.name), ), ), ); // Preserve existing logging (if it was there) - debugPrint( - 'Failed to delete channel: $e\n$st', - ); + debugPrint('Failed to delete channel: $e\n$st'); } }, child: Text( diff --git a/untranslated.json b/untranslated.json index 9e26dfe..d68e753 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1 +1,57 @@ -{} \ No newline at end of file +{ + "bg": [ + "channels_channelDeleteFailed" + ], + + "de": [ + "channels_channelDeleteFailed" + ], + + "es": [ + "channels_channelDeleteFailed" + ], + + "fr": [ + "channels_channelDeleteFailed" + ], + + "it": [ + "channels_channelDeleteFailed" + ], + + "nl": [ + "channels_channelDeleteFailed" + ], + + "pl": [ + "channels_channelDeleteFailed" + ], + + "pt": [ + "channels_channelDeleteFailed" + ], + + "ru": [ + "channels_channelDeleteFailed" + ], + + "sk": [ + "channels_channelDeleteFailed" + ], + + "sl": [ + "channels_channelDeleteFailed" + ], + + "sv": [ + "channels_channelDeleteFailed" + ], + + "uk": [ + "channels_channelDeleteFailed" + ], + + "zh": [ + "channels_channelDeleteFailed" + ] +} From ab76a52d71cf1d476b43cab72b5a5b05522f2a86 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:07:19 -0500 Subject: [PATCH 03/34] Delete .local-agent/AGENTS.local.md --- .local-agent/AGENTS.local.md | 48 ------------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 .local-agent/AGENTS.local.md diff --git a/.local-agent/AGENTS.local.md b/.local-agent/AGENTS.local.md deleted file mode 100644 index 2c61ef8..0000000 --- a/.local-agent/AGENTS.local.md +++ /dev/null @@ -1,48 +0,0 @@ -# Local Agent Operating Rules (Untracked) - -This file is NOT version-controlled. -It overrides default agent behavior for this workstation only. - ---- - -## Core Behavior - -- Always search the codebase before editing. -- Produce a short plan before modifying BLE or protocol logic. -- Never modify BLE frame structure or command codes without explicit approval. -- After editing connector code, re-check command/response mappings. -- Never perform destructive operations (delete files, mass refactor) without confirmation. - ---- - -## Protocol Discipline - -- maxFrameSize must remain 172 unless explicitly instructed. -- Identity hash size is 1 byte (PATH_HASH_SIZE). -- Companion radio formats must not change silently. -- Command codes and response codes must remain backward-compatible. - ---- - -## Coding Discipline - -- Keep modifications minimal. -- Prefer refactoring over rewriting. -- Follow existing Flutter patterns (StatelessWidget + Consumer). -- Avoid premature abstraction. -- Explain what changed and why. - ---- - -## Learning Mode - -When discovering: -- a working build command -- a protocol quirk -- a confirmed packet layout rule - -Append a concise bullet to: - -.local-agent/memory.local.md - -Keep memory under 15 bullets max. From f4dd76a4591b4062930cdcd3bee654a4f1d017bc Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:07:32 -0500 Subject: [PATCH 04/34] Delete .local-agent/memory.local.md --- .local-agent/memory.local.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .local-agent/memory.local.md diff --git a/.local-agent/memory.local.md b/.local-agent/memory.local.md deleted file mode 100644 index a714fbc..0000000 --- a/.local-agent/memory.local.md +++ /dev/null @@ -1,6 +0,0 @@ -\# Local Learned Patterns (Machine-Specific) - -(empty) - - - From 47044ae14e9f8ae2f35edc087d84f866d9ae0858 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:37:10 -0500 Subject: [PATCH 05/34] fix(l10n): add channels_channelDeleteFailed with proper placeholder typing and translations --- lib/l10n/app_bg.arb | 4 ++- lib/l10n/app_de.arb | 4 ++- lib/l10n/app_es.arb | 4 ++- lib/l10n/app_fr.arb | 4 ++- lib/l10n/app_it.arb | 4 ++- lib/l10n/app_localizations_bg.dart | 2 +- lib/l10n/app_localizations_de.dart | 2 +- lib/l10n/app_localizations_es.dart | 2 +- lib/l10n/app_localizations_fr.dart | 2 +- lib/l10n/app_localizations_it.dart | 2 +- lib/l10n/app_localizations_nl.dart | 2 +- lib/l10n/app_localizations_pl.dart | 2 +- lib/l10n/app_localizations_pt.dart | 2 +- lib/l10n/app_localizations_ru.dart | 2 +- lib/l10n/app_localizations_sk.dart | 2 +- lib/l10n/app_localizations_sl.dart | 2 +- lib/l10n/app_localizations_sv.dart | 2 +- lib/l10n/app_localizations_uk.dart | 2 +- lib/l10n/app_localizations_zh.dart | 2 +- lib/l10n/app_nl.arb | 4 ++- lib/l10n/app_pl.arb | 4 ++- lib/l10n/app_pt.arb | 4 ++- lib/l10n/app_ru.arb | 4 ++- lib/l10n/app_sk.arb | 4 ++- lib/l10n/app_sl.arb | 4 ++- lib/l10n/app_sv.arb | 4 ++- lib/l10n/app_uk.arb | 4 ++- lib/l10n/app_zh.arb | 4 ++- pubspec.lock | 20 +++++------ untranslated.json | 58 +----------------------------- 30 files changed, 67 insertions(+), 95 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 8609023..6725c24 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Неуспешно изтриване на канала \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "bg", "appTitle": "MeshCore Open", "nav_contacts": "Контакти", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e5c82f7..dbd0606 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Kanal {name} konnte nicht gelöscht werden", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "de", "appTitle": "MeshCore Open", "nav_contacts": "Kontakte", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 483b4d3..52e7c25 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "No se pudo eliminar el canal \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "es", "appTitle": "MeshCore Open", "nav_contacts": "Contactos", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2d4846c..0e96ba8 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Échec de la suppression de la chaîne \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "fr", "appTitle": "MeshCore Open", "nav_contacts": "Contacts", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 2f8d186..421fcb0 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Impossibile eliminare il canale \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "it", "appTitle": "MeshCore Open", "nav_contacts": "Contatti", diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 25b0631..3876b3c 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -814,7 +814,7 @@ class AppLocalizationsBg extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Неуспешно изтриване на канала \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 9ba8409..96cfee1 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -811,7 +811,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Kanal $name konnte nicht gelöscht werden'; } @override diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 6c9a517..d0e5028 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -812,7 +812,7 @@ class AppLocalizationsEs extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'No se pudo eliminar el canal \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 3b99772..6ad0335 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -814,7 +814,7 @@ class AppLocalizationsFr extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Échec de la suppression de la chaîne \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 7447fad..b53acb5 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -810,7 +810,7 @@ class AppLocalizationsIt extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Impossibile eliminare il canale \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 6e4a2af..fa684e2 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -808,7 +808,7 @@ class AppLocalizationsNl extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Kan kanaal $name niet verwijderen'; } @override diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index dee97c0..b62d4b6 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -813,7 +813,7 @@ class AppLocalizationsPl extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Nie udało się usunąć kanału \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 22c5a2e..34713e6 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -813,7 +813,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Falha ao excluir o canal \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 5afbd87..f0de018 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -811,7 +811,7 @@ class AppLocalizationsRu extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Не удалось удалить канал $name.'; } @override diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 44f5cbf..b826056 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -808,7 +808,7 @@ class AppLocalizationsSk extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Kanál \"$name\" sa nepodarilo odstrániť'; } @override diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 455d5aa..5f2d1a4 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -806,7 +806,7 @@ class AppLocalizationsSl extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Kanala $name ni bilo mogoče izbrisati'; } @override diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 6f94870..6cf18b3 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -802,7 +802,7 @@ class AppLocalizationsSv extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Det gick inte att ta bort kanalen \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 1d6cf23..7869afa 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -809,7 +809,7 @@ class AppLocalizationsUk extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return 'Не вдалося видалити канал \"$name\"'; } @override diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index b297297..ac61263 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -771,7 +771,7 @@ class AppLocalizationsZh extends AppLocalizations { @override String channels_channelDeleteFailed(String name) { - return 'Failed to delete channel \"$name\"'; + return '无法删除频道 \"$name\"'; } @override diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 57b2fdd..f158646 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Kan kanaal {name} niet verwijderen", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "nl", "appTitle": "MeshCore Open", "nav_contacts": "Contacten", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 3787fa7..2eb67dd 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Nie udało się usunąć kanału \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "pl", "appTitle": "MeshCore Open", "nav_contacts": "Kontakty", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 7be6694..4b947ad 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Falha ao excluir o canal \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "pt", "appTitle": "MeshCore Open", "nav_contacts": "Contactos", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 26cfce3..f9ab2d3 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Не удалось удалить канал {name}.", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "ru", "appTitle": "MeshCore Open", "nav_contacts": "Контакты", diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 8b2cb0a..e9653ec 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Kanál \"{name}\" sa nepodarilo odstrániť", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sk", "appTitle": "MeshCore Open", "nav_contacts": "Kontakty", diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 4d3415d..384f669 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Kanala {name} ni bilo mogoče izbrisati", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sl", "appTitle": "MeshCore Open", "nav_contacts": "Stiki", diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 8c5e399..39422fc 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Det gick inte att ta bort kanalen \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sv", "appTitle": "MeshCore Open", "nav_contacts": "Kontakter", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 910f8b0..bb0dd92 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "Не вдалося видалити канал \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "uk", "appTitle": "MeshCore Open", "nav_contacts": "Контакти", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index d9efce7..6bbfe48 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,4 +1,6 @@ -{ +{ + "channels_channelDeleteFailed": "无法删除频道 \"{name}\"", + "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "zh", "appTitle": "MeshCore Open", "nav_contacts": "联系方式", diff --git a/pubspec.lock b/pubspec.lock index ed84c40..09e9301 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -497,26 +497,26 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" mgrs_dart: dependency: transitive description: @@ -910,10 +910,10 @@ packages: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.7" timezone: dependency: transitive description: diff --git a/untranslated.json b/untranslated.json index d68e753..9e26dfe 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,57 +1 @@ -{ - "bg": [ - "channels_channelDeleteFailed" - ], - - "de": [ - "channels_channelDeleteFailed" - ], - - "es": [ - "channels_channelDeleteFailed" - ], - - "fr": [ - "channels_channelDeleteFailed" - ], - - "it": [ - "channels_channelDeleteFailed" - ], - - "nl": [ - "channels_channelDeleteFailed" - ], - - "pl": [ - "channels_channelDeleteFailed" - ], - - "pt": [ - "channels_channelDeleteFailed" - ], - - "ru": [ - "channels_channelDeleteFailed" - ], - - "sk": [ - "channels_channelDeleteFailed" - ], - - "sl": [ - "channels_channelDeleteFailed" - ], - - "sv": [ - "channels_channelDeleteFailed" - ], - - "uk": [ - "channels_channelDeleteFailed" - ], - - "zh": [ - "channels_channelDeleteFailed" - ] -} +{} \ No newline at end of file From f3db63ceeaf590c8042a75999356b6a5be51c1af Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:37:58 -0500 Subject: [PATCH 06/34] Delete pubspec.lock --- pubspec.lock | 1095 -------------------------------------------------- 1 file changed, 1095 deletions(-) delete mode 100644 pubspec.lock diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 09e9301..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,1095 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - archive: - dependency: transitive - description: - name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" - source: hosted - version: "4.0.7" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - bluez: - dependency: transitive - description: - name: bluez - sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" - url: "https://pub.dev" - source: hosted - version: "0.8.3" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - cached_network_image: - dependency: "direct main" - description: - name: cached_network_image - sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - characters: - dependency: "direct main" - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.dev" - source: hosted - version: "0.3.5+2" - crypto: - dependency: "direct main" - description: - name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" - source: hosted - version: "3.0.7" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - dart_earcut: - dependency: transitive - description: - name: dart_earcut - sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b - url: "https://pub.dev" - source: hosted - version: "1.2.0" - dart_polylabel2: - dependency: transitive - description: - name: dart_polylabel2 - sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - dbus: - dependency: transitive - description: - name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.dev" - source: hosted - version: "0.7.12" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_blue_plus: - dependency: "direct main" - description: - name: flutter_blue_plus - sha256: "88a65ead7dea67ddcc03e6ca846163c6b6cc09a2dcebdb8bb601fcd654ea9382" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - flutter_blue_plus_android: - dependency: transitive - description: - name: flutter_blue_plus_android - sha256: "5010b0960cce533a8fa71401573f044362c3e2e111dc6eb4898c92e85f85f50c" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_darwin: - dependency: transitive - description: - name: flutter_blue_plus_darwin - sha256: "52b155d868e17c1c8ad85520a0912d447d92aedccb5a5e234d3edc98ebd1307a" - url: "https://pub.dev" - source: hosted - version: "8.1.1" - flutter_blue_plus_linux: - dependency: transitive - description: - name: flutter_blue_plus_linux - sha256: f5b02244d89465ba82c8c512686c66362fbb01f52fa03d645ed353ebf3883242 - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_platform_interface: - dependency: transitive - description: - name: flutter_blue_plus_platform_interface - sha256: "6e0fc04b77491dbfdbcd46c1a021b12f2f5fc5d6e01777f93a38a8431989b7f0" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_web: - dependency: transitive - description: - name: flutter_blue_plus_web - sha256: "376aad9595ee389c7cd56e0c373e78abcaa790c821ece9cb81f0969ec94c5bca" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_winrt: - dependency: transitive - description: - name: flutter_blue_plus_winrt - sha256: ed894f0ab341f4cece8fa33edc381d46424a7c5bfd0e841d933d0f8c34c86521 - url: "https://pub.dev" - source: hosted - version: "0.0.18" - flutter_cache_manager: - dependency: "direct main" - description: - name: flutter_cache_manager - sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - flutter_foreground_task: - dependency: "direct main" - description: - name: flutter_foreground_task - sha256: "48ea45056155a99fb30b15f14f4039a044d925bc85f381ed0b2d3b00a60b99de" - url: "https://pub.dev" - source: hosted - version: "9.2.0" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" - url: "https://pub.dev" - source: hosted - version: "0.14.4" - flutter_linkify: - dependency: "direct main" - description: - name: flutter_linkify - sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications: - dependency: "direct main" - description: - name: flutter_local_notifications - sha256: "2b50e938a275e1ad77352d6a25e25770f4130baa61eaf02de7a9a884680954ad" - url: "https://pub.dev" - source: hosted - version: "20.1.0" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: dce0116868cedd2cdf768af0365fc37ff1cbef7c02c4f51d0587482e625868d0 - url: "https://pub.dev" - source: hosted - version: "7.0.0" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "23de31678a48c084169d7ae95866df9de5c9d2a44be3e5915a2ff067aeeba899" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - flutter_local_notifications_windows: - dependency: transitive - description: - name: flutter_local_notifications_windows - sha256: e97a1a3016512437d9c0b12fae7d1491c3c7b9aa7f03a69b974308840656b02a - url: "https://pub.dev" - source: hosted - version: "2.0.1" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_map: - dependency: "direct main" - description: - name: flutter_map - sha256: "391e7dc95cc3f5190748210a69d4cfeb5d8f84dcdfa9c3235d0a9d7742ccb3f8" - url: "https://pub.dev" - source: hosted - version: "8.2.2" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - gpx: - dependency: "direct main" - description: - name: gpx - sha256: f5b12b86402c639079243600ee2b3afd85cd08d26117fc8885cf48efce471d8e - url: "https://pub.dev" - source: hosted - version: "2.3.0" - hooks: - dependency: transitive - description: - name: hooks - sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - http: - dependency: "direct main" - description: - name: http - sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image: - dependency: transitive - description: - name: image - sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c" - url: "https://pub.dev" - source: hosted - version: "4.7.2" - intl: - dependency: "direct main" - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "805fa86df56383000f640384b282ce0cb8431f1a7a2396de92fb66186d8c57df" - url: "https://pub.dev" - source: hosted - version: "4.10.0" - latlong2: - dependency: "direct main" - description: - name: latlong2 - sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" - url: "https://pub.dev" - source: hosted - version: "0.9.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - linkify: - dependency: transitive - description: - name: linkify - sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - lints: - dependency: transitive - description: - name: lints - sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - lists: - dependency: transitive - description: - name: lists - sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - logger: - dependency: transitive - description: - name: logger - sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 - url: "https://pub.dev" - source: hosted - version: "2.6.2" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - mgrs_dart: - dependency: transitive - description: - name: mgrs_dart - sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mobile_scanner: - dependency: "direct main" - description: - name: mobile_scanner - sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 - url: "https://pub.dev" - source: hosted - version: "7.1.4" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" - url: "https://pub.dev" - source: hosted - version: "0.17.4" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - package_info_plus: - dependency: "direct main" - description: - name: package_info_plus - sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d - url: "https://pub.dev" - source: hosted - version: "9.0.0" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" - source: hosted - version: "2.2.22" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" - source: hosted - version: "2.6.0" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.dev" - source: hosted - version: "7.0.1" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pointycastle: - dependency: "direct main" - description: - name: pointycastle - sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - posix: - dependency: transitive - description: - name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" - source: hosted - version: "6.0.3" - proj4dart: - dependency: transitive - description: - name: proj4dart - sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e - url: "https://pub.dev" - source: hosted - version: "2.1.0" - provider: - dependency: "direct main" - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - qr: - dependency: transitive - description: - name: qr - sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - qr_flutter: - dependency: "direct main" - description: - name: qr_flutter - sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" - url: "https://pub.dev" - source: hosted - version: "4.1.0" - quiver: - dependency: transitive - description: - name: quiver - sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - share_plus: - dependency: "direct main" - description: - name: share_plus - sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" - url: "https://pub.dev" - source: hosted - version: "12.0.1" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f - url: "https://pub.dev" - source: hosted - version: "2.4.20" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" - source: hosted - version: "1.10.2" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 - url: "https://pub.dev" - source: hosted - version: "2.4.2+2" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 - url: "https://pub.dev" - source: hosted - version: "3.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - timezone: - dependency: transitive - description: - name: timezone - sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - unicode: - dependency: transitive - description: - name: unicode - sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" - source: hosted - version: "2.4.2" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - uuid: - dependency: "direct main" - description: - name: uuid - sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 - url: "https://pub.dev" - source: hosted - version: "4.5.2" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" - wakelock_plus: - dependency: "direct main" - description: - name: wakelock_plus - sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - wakelock_plus_platform_interface: - dependency: transitive - description: - name: wakelock_plus_platform_interface - sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - win32: - dependency: transitive - description: - name: win32 - sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" - source: hosted - version: "5.15.0" - wkt_parser: - dependency: transitive - description: - name: wkt_parser - sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" - source: hosted - version: "6.6.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" From 298951f8bc39951f7fe6ed612ca7bb356111429b Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 18:43:37 -0500 Subject: [PATCH 07/34] bring up to current main --- pubspec.lock | 1095 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1095 insertions(+) create mode 100644 pubspec.lock diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..492eb4d --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1095 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + bluez: + dependency: transitive + description: + name: bluez + sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" + url: "https://pub.dev" + source: hosted + version: "0.8.3" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + characters: + dependency: "direct main" + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + url: "https://pub.dev" + source: hosted + version: "0.3.5+2" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_earcut: + dependency: transitive + description: + name: dart_earcut + sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b + url: "https://pub.dev" + source: hosted + version: "1.2.0" + dart_polylabel2: + dependency: transitive + description: + name: dart_polylabel2 + sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blue_plus: + dependency: "direct main" + description: + name: flutter_blue_plus + sha256: "88a65ead7dea67ddcc03e6ca846163c6b6cc09a2dcebdb8bb601fcd654ea9382" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + flutter_blue_plus_android: + dependency: transitive + description: + name: flutter_blue_plus_android + sha256: "5010b0960cce533a8fa71401573f044362c3e2e111dc6eb4898c92e85f85f50c" + url: "https://pub.dev" + source: hosted + version: "8.1.0" + flutter_blue_plus_darwin: + dependency: transitive + description: + name: flutter_blue_plus_darwin + sha256: "52b155d868e17c1c8ad85520a0912d447d92aedccb5a5e234d3edc98ebd1307a" + url: "https://pub.dev" + source: hosted + version: "8.1.1" + flutter_blue_plus_linux: + dependency: transitive + description: + name: flutter_blue_plus_linux + sha256: f5b02244d89465ba82c8c512686c66362fbb01f52fa03d645ed353ebf3883242 + url: "https://pub.dev" + source: hosted + version: "8.1.0" + flutter_blue_plus_platform_interface: + dependency: transitive + description: + name: flutter_blue_plus_platform_interface + sha256: "6e0fc04b77491dbfdbcd46c1a021b12f2f5fc5d6e01777f93a38a8431989b7f0" + url: "https://pub.dev" + source: hosted + version: "8.1.0" + flutter_blue_plus_web: + dependency: transitive + description: + name: flutter_blue_plus_web + sha256: "376aad9595ee389c7cd56e0c373e78abcaa790c821ece9cb81f0969ec94c5bca" + url: "https://pub.dev" + source: hosted + version: "8.1.0" + flutter_blue_plus_winrt: + dependency: transitive + description: + name: flutter_blue_plus_winrt + sha256: ed894f0ab341f4cece8fa33edc381d46424a7c5bfd0e841d933d0f8c34c86521 + url: "https://pub.dev" + source: hosted + version: "0.0.18" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flutter_foreground_task: + dependency: "direct main" + description: + name: flutter_foreground_task + sha256: "48ea45056155a99fb30b15f14f4039a044d925bc85f381ed0b2d3b00a60b99de" + url: "https://pub.dev" + source: hosted + version: "9.2.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" + source: hosted + version: "0.14.4" + flutter_linkify: + dependency: "direct main" + description: + name: flutter_linkify + sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "2b50e938a275e1ad77352d6a25e25770f4130baa61eaf02de7a9a884680954ad" + url: "https://pub.dev" + source: hosted + version: "20.1.0" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: dce0116868cedd2cdf768af0365fc37ff1cbef7c02c4f51d0587482e625868d0 + url: "https://pub.dev" + source: hosted + version: "7.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "23de31678a48c084169d7ae95866df9de5c9d2a44be3e5915a2ff067aeeba899" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + flutter_local_notifications_windows: + dependency: transitive + description: + name: flutter_local_notifications_windows + sha256: e97a1a3016512437d9c0b12fae7d1491c3c7b9aa7f03a69b974308840656b02a + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: "391e7dc95cc3f5190748210a69d4cfeb5d8f84dcdfa9c3235d0a9d7742ccb3f8" + url: "https://pub.dev" + source: hosted + version: "8.2.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + gpx: + dependency: "direct main" + description: + name: gpx + sha256: f5b12b86402c639079243600ee2b3afd85cd08d26117fc8885cf48efce471d8e + url: "https://pub.dev" + source: hosted + version: "2.3.0" + hooks: + dependency: transitive + description: + name: hooks + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image: + dependency: transitive + description: + name: image + sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c" + url: "https://pub.dev" + source: hosted + version: "4.7.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "805fa86df56383000f640384b282ce0cb8431f1a7a2396de92fb66186d8c57df" + url: "https://pub.dev" + source: hosted + version: "4.10.0" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + linkify: + dependency: transitive + description: + name: linkify + sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + lints: + dependency: transitive + description: + name: lints + sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + logger: + dependency: transitive + description: + name: logger + sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 + url: "https://pub.dev" + source: hosted + version: "2.6.2" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + url: "https://pub.dev" + source: hosted + version: "0.12.18" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + url: "https://pub.dev" + source: hosted + version: "1.18.0" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mobile_scanner: + dependency: "direct main" + description: + name: mobile_scanner + sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 + url: "https://pub.dev" + source: hosted + version: "7.1.4" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" + url: "https://pub.dev" + source: hosted + version: "0.17.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d + url: "https://pub.dev" + source: hosted + version: "9.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + url: "https://pub.dev" + source: hosted + version: "2.2.22" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: "direct main" + description: + name: pointycastle + sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + posix: + dependency: transitive + description: + name: posix + sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + qr: + dependency: transitive + description: + name: qr + sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + qr_flutter: + dependency: "direct main" + description: + name: qr_flutter + sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" + url: "https://pub.dev" + source: hosted + version: "12.0.1" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f + url: "https://pub.dev" + source: hosted + version: "2.4.20" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + url: "https://pub.dev" + source: hosted + version: "0.7.9" + timezone: + dependency: transitive + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" + url: "https://pub.dev" + source: hosted + version: "6.3.28" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + url: "https://pub.dev" + source: hosted + version: "3.2.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + url: "https://pub.dev" + source: hosted + version: "2.4.2" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + url: "https://pub.dev" + source: hosted + version: "4.5.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + wakelock_plus: + dependency: "direct main" + description: + name: wakelock_plus + sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" \ No newline at end of file From 0f2d18d6fa797f7d7ed9bb05af4fd3a0f67cc810 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 23:39:52 -0500 Subject: [PATCH 08/34] feat: add custom los icon --- lib/icons/los_icon.dart | 26 ++++++++++ lib/screens/line_of_sight_map_screen.dart | 3 +- lib/screens/map_screen.dart | 3 +- pubspec.lock | 60 +++++++++++++++++++---- pubspec.yaml | 1 + 5 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 lib/icons/los_icon.dart diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart new file mode 100644 index 0000000..309cc7d --- /dev/null +++ b/lib/icons/los_icon.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class LosIcon extends StatelessWidget { + final double size; + final Color? color; + + const LosIcon({super.key, this.size = 24, this.color}); + + @override + Widget build(BuildContext context) { + final iconColor = color ?? IconTheme.of(context).color ?? Colors.black; + return SvgPicture.string( + _losSvg, + width: size, + height: size, + colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn), + ); + } +} + +const String _losSvg = ''' + + + +'''; diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index b073685..dfda1c1 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -16,6 +16,7 @@ import '../services/map_tile_cache_service.dart'; import '../utils/route_transitions.dart'; import '../widgets/app_bar.dart'; import '../widgets/quick_switch_bar.dart'; +import '../icons/los_icon.dart'; class LineOfSightEndpoint { final String label; @@ -642,7 +643,7 @@ class _LineOfSightMapScreenState extends State { alignment: Alignment.centerRight, child: ElevatedButton.icon( onPressed: _loading ? null : _runLos, - icon: const Icon(Icons.visibility), + icon: const LosIcon(), label: Text(context.l10n.losRun), ), ), diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index 77ec98c..b688a30 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -20,6 +20,7 @@ import '../services/map_tile_cache_service.dart'; import '../utils/contact_search.dart'; import '../utils/route_transitions.dart'; import '../widgets/quick_switch_bar.dart'; +import '../icons/los_icon.dart'; import 'channels_screen.dart'; import 'chat_screen.dart'; import 'contacts_screen.dart'; @@ -280,7 +281,7 @@ class _MapScreenState extends State { ), if (!_isBuildingPathTrace) IconButton( - icon: const Icon(Icons.visibility), + icon: const LosIcon(), onPressed: () { final candidates = []; if (connector.selfLatitude != null && diff --git a/pubspec.lock b/pubspec.lock index ed84c40..d9d480f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -347,6 +347,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.2" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" + url: "https://pub.dev" + source: hosted + version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -497,26 +505,26 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" mgrs_dart: dependency: transitive description: @@ -597,6 +605,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -910,10 +926,10 @@ packages: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.7" timezone: dependency: transitive description: @@ -1010,6 +1026,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + url: "https://pub.dev" + source: hosted + version: "1.2.0" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3624b93..54e3648 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,7 @@ dependencies: gpx: ^2.3.0 path_provider: ^2.1.5 share_plus: ^12.0.1 + flutter_svg: ^2.0.10 dev_dependencies: flutter_test: From 08edd2696ee33a8376d2fb244d3bc6cf0ca6e560 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Sun, 22 Feb 2026 23:47:49 -0500 Subject: [PATCH 09/34] Revert "feat: add custom los icon" This reverts commit 0f2d18d6fa797f7d7ed9bb05af4fd3a0f67cc810. --- lib/icons/los_icon.dart | 26 ---------- lib/screens/line_of_sight_map_screen.dart | 3 +- lib/screens/map_screen.dart | 3 +- pubspec.lock | 60 ++++------------------- pubspec.yaml | 1 - 5 files changed, 12 insertions(+), 81 deletions(-) delete mode 100644 lib/icons/los_icon.dart diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart deleted file mode 100644 index 309cc7d..0000000 --- a/lib/icons/los_icon.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; - -class LosIcon extends StatelessWidget { - final double size; - final Color? color; - - const LosIcon({super.key, this.size = 24, this.color}); - - @override - Widget build(BuildContext context) { - final iconColor = color ?? IconTheme.of(context).color ?? Colors.black; - return SvgPicture.string( - _losSvg, - width: size, - height: size, - colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn), - ); - } -} - -const String _losSvg = ''' - - - -'''; diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index dfda1c1..b073685 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -16,7 +16,6 @@ import '../services/map_tile_cache_service.dart'; import '../utils/route_transitions.dart'; import '../widgets/app_bar.dart'; import '../widgets/quick_switch_bar.dart'; -import '../icons/los_icon.dart'; class LineOfSightEndpoint { final String label; @@ -643,7 +642,7 @@ class _LineOfSightMapScreenState extends State { alignment: Alignment.centerRight, child: ElevatedButton.icon( onPressed: _loading ? null : _runLos, - icon: const LosIcon(), + icon: const Icon(Icons.visibility), label: Text(context.l10n.losRun), ), ), diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index b688a30..77ec98c 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -20,7 +20,6 @@ import '../services/map_tile_cache_service.dart'; import '../utils/contact_search.dart'; import '../utils/route_transitions.dart'; import '../widgets/quick_switch_bar.dart'; -import '../icons/los_icon.dart'; import 'channels_screen.dart'; import 'chat_screen.dart'; import 'contacts_screen.dart'; @@ -281,7 +280,7 @@ class _MapScreenState extends State { ), if (!_isBuildingPathTrace) IconButton( - icon: const LosIcon(), + icon: const Icon(Icons.visibility), onPressed: () { final candidates = []; if (connector.selfLatitude != null && diff --git a/pubspec.lock b/pubspec.lock index d9d480f..ed84c40 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" checked_yaml: dependency: transitive description: @@ -347,14 +347,6 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.2" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" - source: hosted - version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -505,26 +497,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.18" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" mgrs_dart: dependency: transitive description: @@ -605,14 +597,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" path_provider: dependency: "direct main" description: @@ -926,10 +910,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.9" timezone: dependency: transitive description: @@ -1026,30 +1010,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.2" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" - url: "https://pub.dev" - source: hosted - version: "1.2.0" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 54e3648..3624b93 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,7 +60,6 @@ dependencies: gpx: ^2.3.0 path_provider: ^2.1.5 share_plus: ^12.0.1 - flutter_svg: ^2.0.10 dev_dependencies: flutter_test: From aaf79c90c91a987527d811a6dfe22142c3d07724 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 00:01:13 -0500 Subject: [PATCH 10/34] feat: show los elevation icon --- lib/icons/los_icon.dart | 80 +++++++++++++++++++++++ lib/screens/line_of_sight_map_screen.dart | 3 +- lib/screens/map_screen.dart | 3 +- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 lib/icons/los_icon.dart diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart new file mode 100644 index 0000000..86bef06 --- /dev/null +++ b/lib/icons/los_icon.dart @@ -0,0 +1,80 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; + +class LosIcon extends StatelessWidget { + final double size; + final Color? color; + + const LosIcon({ + super.key, + this.size = 24, + this.color, + }); + + @override + Widget build(BuildContext context) { + final iconColor = color ?? IconTheme.of(context).color ?? Colors.black; + final canvasSize = size; + + return SizedBox( + width: canvasSize, + height: canvasSize, + child: CustomPaint( + painter: _LosIconPainter(iconColor), + ), + ); + } +} + +class _LosIconPainter extends CustomPainter { + final Color color; + + _LosIconPainter(this.color); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color + ..style = PaintingStyle.fill; + + final path = Path() + ..moveTo(82, -120) + ..relativeLineTo(258, -360) + ..relativeLineTo(202, 0) + ..relativeLineTo(298, -348) + ..relativeLineTo(0, 708) + ..lineTo(82, -120) + ..close() + ..moveTo(152, -353) + ..relativeLineTo(-64, -46) + ..relativeLineTo(172, -241) + ..relativeLineTo(202, 0) + ..relativeLineTo(188, -219) + ..relativeLineTo(60, 52) + ..relativeLineTo(-212, 247) + ..lineTo(300, -560) + ..lineTo(152, -353) + ..close() + ..moveTo(238, -200) + ..relativeLineTo(522, 0) + ..relativeLineTo(0, -412) + ..lineTo(578, -400) + ..lineTo(380, -400) + ..lineTo(238, -200) + ..close(); + + final scale = math.min(size.width, size.height) / 960; + + canvas.save(); + canvas.translate(0, 960); + canvas.scale(scale, scale); + canvas.drawPath(path, paint); + canvas.restore(); + } + + @override + bool shouldRepaint(covariant _LosIconPainter oldDelegate) { + return oldDelegate.color != color; + } +} diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index b073685..dfda1c1 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -16,6 +16,7 @@ import '../services/map_tile_cache_service.dart'; import '../utils/route_transitions.dart'; import '../widgets/app_bar.dart'; import '../widgets/quick_switch_bar.dart'; +import '../icons/los_icon.dart'; class LineOfSightEndpoint { final String label; @@ -642,7 +643,7 @@ class _LineOfSightMapScreenState extends State { alignment: Alignment.centerRight, child: ElevatedButton.icon( onPressed: _loading ? null : _runLos, - icon: const Icon(Icons.visibility), + icon: const LosIcon(), label: Text(context.l10n.losRun), ), ), diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index 77ec98c..b688a30 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -20,6 +20,7 @@ import '../services/map_tile_cache_service.dart'; import '../utils/contact_search.dart'; import '../utils/route_transitions.dart'; import '../widgets/quick_switch_bar.dart'; +import '../icons/los_icon.dart'; import 'channels_screen.dart'; import 'chat_screen.dart'; import 'contacts_screen.dart'; @@ -280,7 +281,7 @@ class _MapScreenState extends State { ), if (!_isBuildingPathTrace) IconButton( - icon: const Icon(Icons.visibility), + icon: const LosIcon(), onPressed: () { final candidates = []; if (connector.selfLatitude != null && From 9bcb8b9ca67d6478dff1ca3fcf3b6481bca5d1dd Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 00:36:49 -0500 Subject: [PATCH 11/34] feat: render los elevation via svg --- assets/icons/los_elevation.svg | 5 +++ lib/icons/los_icon.dart | 68 +++------------------------------- pubspec.lock | 68 +++++++++++++++++++++++++++------- pubspec.yaml | 2 + 4 files changed, 67 insertions(+), 76 deletions(-) create mode 100644 assets/icons/los_elevation.svg diff --git a/assets/icons/los_elevation.svg b/assets/icons/los_elevation.svg new file mode 100644 index 0000000..78c7a1b --- /dev/null +++ b/assets/icons/los_elevation.svg @@ -0,0 +1,5 @@ + + + diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart index 86bef06..fef6a45 100644 --- a/lib/icons/los_icon.dart +++ b/lib/icons/los_icon.dart @@ -1,6 +1,5 @@ -import 'dart:math' as math; - import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; class LosIcon extends StatelessWidget { final double size; @@ -15,66 +14,11 @@ class LosIcon extends StatelessWidget { @override Widget build(BuildContext context) { final iconColor = color ?? IconTheme.of(context).color ?? Colors.black; - final canvasSize = size; - - return SizedBox( - width: canvasSize, - height: canvasSize, - child: CustomPaint( - painter: _LosIconPainter(iconColor), - ), + return SvgPicture.asset( + 'assets/icons/los_elevation.svg', + width: size, + height: size, + colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn), ); } } - -class _LosIconPainter extends CustomPainter { - final Color color; - - _LosIconPainter(this.color); - - @override - void paint(Canvas canvas, Size size) { - final paint = Paint() - ..color = color - ..style = PaintingStyle.fill; - - final path = Path() - ..moveTo(82, -120) - ..relativeLineTo(258, -360) - ..relativeLineTo(202, 0) - ..relativeLineTo(298, -348) - ..relativeLineTo(0, 708) - ..lineTo(82, -120) - ..close() - ..moveTo(152, -353) - ..relativeLineTo(-64, -46) - ..relativeLineTo(172, -241) - ..relativeLineTo(202, 0) - ..relativeLineTo(188, -219) - ..relativeLineTo(60, 52) - ..relativeLineTo(-212, 247) - ..lineTo(300, -560) - ..lineTo(152, -353) - ..close() - ..moveTo(238, -200) - ..relativeLineTo(522, 0) - ..relativeLineTo(0, -412) - ..lineTo(578, -400) - ..lineTo(380, -400) - ..lineTo(238, -200) - ..close(); - - final scale = math.min(size.width, size.height) / 960; - - canvas.save(); - canvas.translate(0, 960); - canvas.scale(scale, scale); - canvas.drawPath(path, paint); - canvas.restore(); - } - - @override - bool shouldRepaint(covariant _LosIconPainter oldDelegate) { - return oldDelegate.color != color; - } -} diff --git a/pubspec.lock b/pubspec.lock index ed84c40..266bfb7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: @@ -347,6 +347,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.2" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" + url: "https://pub.dev" + source: hosted + version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -401,10 +409,10 @@ packages: dependency: transitive description: name: image - sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c" + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce url: "https://pub.dev" source: hosted - version: "4.7.2" + version: "4.8.0" intl: dependency: "direct main" description: @@ -417,10 +425,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: "805fa86df56383000f640384b282ce0cb8431f1a7a2396de92fb66186d8c57df" + sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.11.0" latlong2: dependency: "direct main" description: @@ -537,10 +545,10 @@ packages: dependency: "direct main" description: name: mobile_scanner - sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 + sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce url: "https://pub.dev" source: hosted - version: "7.1.4" + version: "7.2.0" native_toolchain_c: dependency: transitive description: @@ -597,6 +605,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -649,10 +665,10 @@ packages: dependency: transitive description: name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.2" platform: dependency: transitive description: @@ -681,10 +697,10 @@ packages: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.5.0" proj4dart: dependency: transitive description: @@ -1006,10 +1022,34 @@ packages: dependency: "direct main" description: name: uuid - sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" url: "https://pub.dev" source: hosted - version: "4.5.2" + version: "4.5.3" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + url: "https://pub.dev" + source: hosted + version: "1.2.0" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3624b93..3dc40d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,7 @@ dependencies: gpx: ^2.3.0 path_provider: ^2.1.5 share_plus: ^12.0.1 + flutter_svg: ^2.0.10 dev_dependencies: flutter_test: @@ -87,6 +88,7 @@ flutter: assets: - assets/images/ + - assets/icons/los_elevation.svg flutter_launcher_icons: android: true From bd27c90216c70eadec03e375d3de9aeb60537626 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 00:42:36 -0500 Subject: [PATCH 12/34] feat: render los elevation via material symbol --- assets/icons/los_elevation.svg | 5 ---- lib/icons/los_icon.dart | 19 +++++++++----- pubspec.lock | 48 ++++++---------------------------- pubspec.yaml | 3 +-- 4 files changed, 21 insertions(+), 54 deletions(-) delete mode 100644 assets/icons/los_elevation.svg diff --git a/assets/icons/los_elevation.svg b/assets/icons/los_elevation.svg deleted file mode 100644 index 78c7a1b..0000000 --- a/assets/icons/los_elevation.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart index fef6a45..43c6cdc 100644 --- a/lib/icons/los_icon.dart +++ b/lib/icons/los_icon.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:material_symbols_icons/material_symbols_icons.dart'; class LosIcon extends StatelessWidget { final double size; @@ -13,12 +13,17 @@ class LosIcon extends StatelessWidget { @override Widget build(BuildContext context) { - final iconColor = color ?? IconTheme.of(context).color ?? Colors.black; - return SvgPicture.asset( - 'assets/icons/los_elevation.svg', - width: size, - height: size, - colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn), + final theme = Theme.of(context); + final iconTheme = IconTheme.of(context); + final iconColor = color ?? + iconTheme.color ?? + theme.iconTheme.color ?? + theme.colorScheme.onSurface; + + return Icon( + Symbols.elevation, + size: size, + color: iconColor, ); } } diff --git a/pubspec.lock b/pubspec.lock index 266bfb7..9605e96 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -347,14 +347,6 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.2" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" - source: hosted - version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -517,6 +509,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.0" + material_symbols_icons: + dependency: "direct main" + description: + name: material_symbols_icons + sha256: c62b15f2b3de98d72cbff0148812f5ef5159f05e61fc9f9a089ec2bb234df082 + url: "https://pub.dev" + source: hosted + version: "4.2906.0" meta: dependency: transitive description: @@ -605,14 +605,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" path_provider: dependency: "direct main" description: @@ -1026,30 +1018,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.3" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" - url: "https://pub.dev" - source: hosted - version: "1.2.0" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3dc40d5..7d6b5c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,7 +60,7 @@ dependencies: gpx: ^2.3.0 path_provider: ^2.1.5 share_plus: ^12.0.1 - flutter_svg: ^2.0.10 + material_symbols_icons: ^4.2906.0 dev_dependencies: flutter_test: @@ -88,7 +88,6 @@ flutter: assets: - assets/images/ - - assets/icons/los_elevation.svg flutter_launcher_icons: android: true From 1f816f7e087d5c85be2c763d22bf19a4a11951ab Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 01:06:25 -0500 Subject: [PATCH 13/34] ran dart format . on libs/icons/los_icon.dart --- lib/icons/los_icon.dart | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/icons/los_icon.dart b/lib/icons/los_icon.dart index 43c6cdc..58d75b0 100644 --- a/lib/icons/los_icon.dart +++ b/lib/icons/los_icon.dart @@ -5,25 +5,18 @@ class LosIcon extends StatelessWidget { final double size; final Color? color; - const LosIcon({ - super.key, - this.size = 24, - this.color, - }); + const LosIcon({super.key, this.size = 24, this.color}); @override Widget build(BuildContext context) { final theme = Theme.of(context); final iconTheme = IconTheme.of(context); - final iconColor = color ?? + final iconColor = + color ?? iconTheme.color ?? theme.iconTheme.color ?? theme.colorScheme.onSurface; - return Icon( - Symbols.elevation, - size: size, - color: iconColor, - ); + return Icon(Symbols.elevation, size: size, color: iconColor); } } From 2bdd9d35cc8a1eee151bb2d353df845087c72841 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 01:53:41 -0500 Subject: [PATCH 14/34] feat: show radio horizon on los profile --- lib/screens/line_of_sight_map_screen.dart | 154 +++++++++++++++++++++- lib/services/line_of_sight_service.dart | 4 + 2 files changed, 155 insertions(+), 3 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index b073685..101f013 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -943,7 +943,10 @@ class _LosProfilePainter extends CustomPainter { terrainPath.lineTo(size.width, size.height); terrainPath.close(); - canvas.drawPath(terrainPath, Paint()..color = const Color(0xCC7C6F5D)); + const terrainFillColor = Color(0xCC7C6F5D); + const terrainLineColor = Color(0xFF9FE870); + const losLineColor = Color(0xFFE0E7FF); + canvas.drawPath(terrainPath, Paint()..color = terrainFillColor); final terrainLine = ui.Path(); for (int i = 0; i < samples.length; i++) { @@ -957,7 +960,7 @@ class _LosProfilePainter extends CustomPainter { canvas.drawPath( terrainLine, Paint() - ..color = const Color(0xFF9FE870) + ..color = terrainLineColor ..style = PaintingStyle.stroke ..strokeWidth = 2, ); @@ -977,10 +980,64 @@ class _LosProfilePainter extends CustomPainter { canvas.drawPath( losLine, Paint() - ..color = const Color(0xFFE0E7FF) + ..color = losLineColor ..style = PaintingStyle.stroke ..strokeWidth = 2, ); + + final horizonLine = ui.Path(); + for (int i = 0; i < samples.length; i++) { + final p = mapPoint( + samples[i].distanceMeters, + samples[i].radioHorizonMeters, + ); + if (i == 0) { + horizonLine.moveTo(p.dx, p.dy); + } else { + horizonLine.lineTo(p.dx, p.dy); + } + } + const horizonLineColor = Color(0xFF4BC0FF); + final horizonPaint = Paint() + ..color = horizonLineColor + ..style = PaintingStyle.stroke + ..strokeWidth = 1.5; + canvas.drawPath(horizonLine, horizonPaint); + + final capPath = ui.Path(); + for (int i = 0; i < samples.length; i++) { + final p = mapPoint( + samples[i].distanceMeters, + samples[i].radioHorizonMeters, + ); + if (i == 0) { + capPath.moveTo(p.dx, p.dy); + } else { + capPath.lineTo(p.dx, p.dy); + } + } + for (int i = samples.length - 1; i >= 0; i--) { + final p = mapPoint( + samples[i].distanceMeters, + samples[i].lineHeightMeters, + ); + capPath.lineTo(p.dx, p.dy); + } + capPath.close(); + const horizonFillColor = Color(0x404BC0FF); + canvas.drawPath( + capPath, + Paint() + ..color = horizonFillColor + ..style = PaintingStyle.fill, + ); + + _drawLegend( + canvas, + horizonLineColor, + losLineColor, + terrainLineColor, + ); } @override @@ -1000,4 +1057,95 @@ class _LosProfilePainter extends CustomPainter { ..layout(); painter.paint(canvas, Offset(size.width - painter.width - 8, 8)); } + + void _drawLegend( + Canvas canvas, + Color horizonColor, + Color losColor, + Color terrainColor, + ) { + const legendX = 8.0; + const legendY = 8.0; + const swatchSize = 10.0; + const swatchTextGap = 6.0; + const entrySpacing = 4.0; + const legendPadding = 6.0; + + final entries = [ + _LegendEntry('Terrain', terrainColor), + _LegendEntry('LOS beam', losColor), + _LegendEntry('Radio horizon', horizonColor), + ]; + + final textStyle = badgeTextStyle.copyWith( + fontSize: 10, + fontWeight: FontWeight.w500, + ); + + final painters = entries.map((entry) { + final painter = TextPainter( + text: TextSpan(text: entry.label, style: textStyle), + textDirection: TextDirection.ltr, + )..layout(); + return painter; + }).toList(); + + final maxTextWidth = painters.map((p) => p.width).fold( + 0, + math.max, + ); + + final legendWidth = + legendPadding * 2 + swatchSize + swatchTextGap + maxTextWidth; + + final legendHeight = legendPadding * 2 + + entries.length * swatchSize + + (entries.length - 1) * entrySpacing; + + final legendRect = RRect.fromLTRBR( + legendX, + legendY, + legendX + legendWidth, + legendY + legendHeight, + const Radius.circular(10), + ); + + canvas.drawRRect( + legendRect, + Paint()..color = const Color.fromARGB(90, 0, 0, 0), + ); + + var yOffset = legendY + legendPadding; + for (int i = 0; i < entries.length; i++) { + final entry = entries[i]; + final painter = painters[i]; + final swatchRect = Rect.fromLTWH( + legendX + legendPadding, + yOffset, + swatchSize, + swatchSize, + ); + canvas.drawRect( + swatchRect, + Paint()..color = entry.color, + ); + + painter.paint( + canvas, + Offset( + swatchRect.right + swatchTextGap, + yOffset + (swatchSize - painter.height) / 2, + ), + ); + + yOffset += swatchSize + entrySpacing; + } + } +} + +class _LegendEntry { + final String label; + final Color color; + + const _LegendEntry(this.label, this.color); } diff --git a/lib/services/line_of_sight_service.dart b/lib/services/line_of_sight_service.dart index e9f9f7b..b73ab51 100644 --- a/lib/services/line_of_sight_service.dart +++ b/lib/services/line_of_sight_service.dart @@ -12,12 +12,14 @@ class LineOfSightSample { final double distanceMeters; final double terrainMeters; final double lineHeightMeters; + final double radioHorizonMeters; final double clearanceMeters; const LineOfSightSample({ required this.distanceMeters, required this.terrainMeters, required this.lineHeightMeters, + required this.radioHorizonMeters, required this.clearanceMeters, }); } @@ -238,6 +240,7 @@ class LineOfSightService { (2 * effectiveEarthRadius); final terrainHeight = elevations[i] + earthBulge; final clearance = lineHeight - terrainHeight; + final radioHorizonHeight = lineHeight - earthBulge; if (clearance < -obstructionToleranceMeters) { isClear = false; @@ -253,6 +256,7 @@ class LineOfSightService { distanceMeters: distanceFromStart, terrainMeters: terrainHeight, lineHeightMeters: lineHeight, + radioHorizonMeters: radioHorizonHeight, clearanceMeters: clearance, ), ); From fc55fb98ce8211166bf3e44a4285b884f43e22e8 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 02:42:58 -0500 Subject: [PATCH 15/34] Document LOS frequency and k-factor math Show the connector frequency right next to the Frequency label, display the derived k value, and keep the info dialog tied to the exact --- lib/screens/line_of_sight_map_screen.dart | 152 ++++++++++++++---- lib/services/line_of_sight_service.dart | 47 +++++- test/services/line_of_sight_service_test.dart | 2 + 3 files changed, 166 insertions(+), 35 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 101f013..5eb532b 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -14,6 +14,7 @@ import '../services/app_settings_service.dart'; import '../services/line_of_sight_service.dart'; import '../services/map_tile_cache_service.dart'; import '../utils/route_transitions.dart'; +import '../connector/meshcore_connector.dart'; import '../widgets/app_bar.dart'; import '../widgets/quick_switch_bar.dart'; @@ -110,10 +111,13 @@ class _LineOfSightMapScreenState extends State { }); try { + final connector = context.read(); + final frequencyMHz = _normalizeFrequencyMHz(connector.currentFreqHz); final result = await _lineOfSightService.analyzePath( [start.point, end.point], startAntennaHeightMeters: startAntenna, endAntennaHeightMeters: endAntenna, + frequencyMHz: frequencyMHz, ); if (!mounted) return; if (!_isRunRequestCurrent( @@ -424,6 +428,12 @@ class _LineOfSightMapScreenState extends State { Widget _buildControlPanel(bool isImperial) { _sanitizeSelection(); final segment = _primarySegmentResult(); + final connector = context.watch(); + final reportedFrequencyMHz = _normalizeFrequencyMHz( + connector.currentFreqHz, + ); + final displayFrequencyMHz = segment?.frequencyMHz ?? reportedFrequencyMHz; + final kFactorUsed = segment?.usedKFactor; final endpoints = _visibleEndpoints(); final distanceUnit = isImperial ? 'mi' : 'km'; final heightUnit = isImperial ? 'ft' : 'm'; @@ -488,6 +498,52 @@ class _LineOfSightMapScreenState extends State { ), ), const SizedBox(height: 4), + if (displayFrequencyMHz != null) + Padding( + padding: const EdgeInsets.only(top: 2, bottom: 4), + child: Row( + children: [ + Text( + 'Frequency', + style: TextStyle( + fontSize: 11, + color: Colors.grey[700], + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(width: 8), + Text( + '${displayFrequencyMHz.toStringAsFixed(3)} MHz', + style: TextStyle(fontSize: 11, color: Colors.grey[700]), + ), + if (kFactorUsed != null) ...[ + const SizedBox(width: 8), + Text( + 'k=${kFactorUsed.toStringAsFixed(3)}', + style: TextStyle( + fontSize: 11, + color: Colors.grey[700], + ), + ), + const SizedBox(width: 4), + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + icon: const Icon(Icons.info_outline, size: 16), + color: Colors.grey[600], + tooltip: 'View calculation details', + onPressed: () { + _showFrequencyInfoDialog( + context, + displayFrequencyMHz, + kFactorUsed, + ); + }, + ), + ], + ], + ), + ), Text( context.l10n.losElevationAttribution, style: TextStyle(fontSize: 10, color: Colors.grey[700]), @@ -896,6 +952,56 @@ class _LineOfSightMapScreenState extends State { break; } } + + void _showFrequencyInfoDialog( + BuildContext context, + double frequencyMHz, + double kFactor, + ) { + final baselineFreq = LineOfSightService.baselineFrequencyMHz; + final baselineK = LineOfSightService.baselineKFactor; + showDialog( + context: context, + builder: (dialogContext) => AlertDialog( + title: const Text('Radio horizon calculation'), + content: Text.rich( + TextSpan( + children: [ + TextSpan( + text: + 'Starting from k=$baselineK at ${baselineFreq.toStringAsFixed(3)} MHz, ', + ), + const TextSpan(text: 'the calculation multiplies the offset by '), + TextSpan( + text: + '0.15 × (frequency − ${baselineFreq.toStringAsFixed(3)}) / ${baselineFreq.toStringAsFixed(3)} ', + ), + TextSpan( + text: + 'to get k ≈ ${kFactor.toStringAsFixed(3)} for the current ${frequencyMHz.toStringAsFixed(3)} MHz band, ', + ), + const TextSpan( + text: 'which defines the curved radio horizon cap.', + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(dialogContext), + child: Text(context.l10n.common_ok), + ), + ], + ), + ); + } + + double? _normalizeFrequencyMHz(int? frequencyHz) { + if (frequencyHz == null || frequencyHz <= 0) return null; + if (frequencyHz >= 1000000) return frequencyHz / 1e6; + if (frequencyHz >= 1000) return frequencyHz / 1e3; + return frequencyHz.toDouble(); + } } class _LosProfilePainter extends CustomPainter { @@ -985,30 +1091,32 @@ class _LosProfilePainter extends CustomPainter { ..strokeWidth = 2, ); - final horizonLine = ui.Path(); + const refractedLineColor = Color(0xFFFFD57F); + final refractedLine = ui.Path(); for (int i = 0; i < samples.length; i++) { final p = mapPoint( samples[i].distanceMeters, - samples[i].radioHorizonMeters, + samples[i].refractedHeightMeters, ); if (i == 0) { - horizonLine.moveTo(p.dx, p.dy); + refractedLine.moveTo(p.dx, p.dy); } else { - horizonLine.lineTo(p.dx, p.dy); + refractedLine.lineTo(p.dx, p.dy); } } - const horizonLineColor = Color(0xFF4BC0FF); - final horizonPaint = Paint() - ..color = horizonLineColor - ..style = PaintingStyle.stroke - ..strokeWidth = 1.5; - canvas.drawPath(horizonLine, horizonPaint); + canvas.drawPath( + refractedLine, + Paint() + ..color = refractedLineColor + ..style = PaintingStyle.stroke + ..strokeWidth = 1.5, + ); final capPath = ui.Path(); for (int i = 0; i < samples.length; i++) { final p = mapPoint( samples[i].distanceMeters, - samples[i].radioHorizonMeters, + samples[i].refractedHeightMeters, ); if (i == 0) { capPath.moveTo(p.dx, p.dy); @@ -1024,7 +1132,7 @@ class _LosProfilePainter extends CustomPainter { capPath.lineTo(p.dx, p.dy); } capPath.close(); - const horizonFillColor = Color(0x404BC0FF); + const horizonFillColor = Color(0x40FFD57F); canvas.drawPath( capPath, Paint() @@ -1032,12 +1140,7 @@ class _LosProfilePainter extends CustomPainter { ..style = PaintingStyle.fill, ); - _drawLegend( - canvas, - horizonLineColor, - losLineColor, - terrainLineColor, - ); + _drawLegend(canvas, refractedLineColor, losLineColor, terrainLineColor); } @override @@ -1090,15 +1193,13 @@ class _LosProfilePainter extends CustomPainter { return painter; }).toList(); - final maxTextWidth = painters.map((p) => p.width).fold( - 0, - math.max, - ); + final maxTextWidth = painters.map((p) => p.width).fold(0, math.max); final legendWidth = legendPadding * 2 + swatchSize + swatchTextGap + maxTextWidth; - final legendHeight = legendPadding * 2 + + final legendHeight = + legendPadding * 2 + entries.length * swatchSize + (entries.length - 1) * entrySpacing; @@ -1125,10 +1226,7 @@ class _LosProfilePainter extends CustomPainter { swatchSize, swatchSize, ); - canvas.drawRect( - swatchRect, - Paint()..color = entry.color, - ); + canvas.drawRect(swatchRect, Paint()..color = entry.color); painter.paint( canvas, diff --git a/lib/services/line_of_sight_service.dart b/lib/services/line_of_sight_service.dart index b73ab51..14d8fc6 100644 --- a/lib/services/line_of_sight_service.dart +++ b/lib/services/line_of_sight_service.dart @@ -12,14 +12,14 @@ class LineOfSightSample { final double distanceMeters; final double terrainMeters; final double lineHeightMeters; - final double radioHorizonMeters; + final double refractedHeightMeters; final double clearanceMeters; const LineOfSightSample({ required this.distanceMeters, required this.terrainMeters, required this.lineHeightMeters, - required this.radioHorizonMeters, + required this.refractedHeightMeters, required this.clearanceMeters, }); } @@ -32,6 +32,8 @@ class LineOfSightResult { final double? firstObstructionDistanceMeters; final List samples; final String? errorMessage; + final double usedKFactor; + final double? frequencyMHz; const LineOfSightResult({ required this.hasData, @@ -40,6 +42,8 @@ class LineOfSightResult { required this.maxObstructionMeters, required this.firstObstructionDistanceMeters, required this.samples, + required this.usedKFactor, + this.frequencyMHz, this.errorMessage, }); @@ -50,7 +54,9 @@ class LineOfSightResult { isClear = false, maxObstructionMeters = 0, firstObstructionDistanceMeters = null, - samples = const []; + samples = const [], + usedKFactor = 4.0 / 3.0, + frequencyMHz = null; } class LineOfSightPathSegment { @@ -91,6 +97,11 @@ class LineOfSightService { static const Duration _cacheTtl = Duration(hours: 24); static const int _maxFetchAttempts = 4; // initial try + 3 retries static const Duration _initialBackoff = Duration(milliseconds: 300); + static const double _baselineFrequencyMHz = 915.0; + static const double _baselineKFactor = 4.0 / 3.0; + + static double get baselineFrequencyMHz => _baselineFrequencyMHz; + static double get baselineKFactor => _baselineKFactor; final http.Client _httpClient; final bool _ownsHttpClient; @@ -108,7 +119,7 @@ class LineOfSightService { List points, { double startAntennaHeightMeters = 1.5, double endAntennaHeightMeters = 1.5, - double kFactor = 4.0 / 3.0, + double? frequencyMHz, double obstructionToleranceMeters = 0.0, }) async { if (points.length < 2) { @@ -125,6 +136,7 @@ class LineOfSightService { var blockedSegments = 0; var unknownSegments = 0; + final kFactor = _kFactorForFrequency(frequencyMHz); for (int i = 0; i < points.length - 1; i++) { final result = await analyzeLink( points[i], @@ -132,6 +144,7 @@ class LineOfSightService { startAntennaHeightMeters: startAntennaHeightMeters, endAntennaHeightMeters: endAntennaHeightMeters, kFactor: kFactor, + frequencyMHz: frequencyMHz, obstructionToleranceMeters: obstructionToleranceMeters, ); segments.add( @@ -165,7 +178,8 @@ class LineOfSightService { LatLng end, { double startAntennaHeightMeters = 1.5, double endAntennaHeightMeters = 1.5, - double kFactor = 4.0 / 3.0, + required double kFactor, + double? frequencyMHz, double obstructionToleranceMeters = 0.0, }) async { final totalDistanceMeters = _distance.as(LengthUnit.Meter, start, end); @@ -177,6 +191,8 @@ class LineOfSightService { maxObstructionMeters: 0, firstObstructionDistanceMeters: null, samples: const [], + usedKFactor: kFactor, + frequencyMHz: frequencyMHz, ); } @@ -205,7 +221,8 @@ class LineOfSightService { required List elevations, double startAntennaHeightMeters = 1.5, double endAntennaHeightMeters = 1.5, - double kFactor = 4.0 / 3.0, + required double kFactor, + double? frequencyMHz, double obstructionToleranceMeters = 0.0, }) { if (points.length < 2 || elevations.length != points.length) { @@ -240,7 +257,10 @@ class LineOfSightService { (2 * effectiveEarthRadius); final terrainHeight = elevations[i] + earthBulge; final clearance = lineHeight - terrainHeight; - final radioHorizonHeight = lineHeight - earthBulge; + final unrefBulge = + (distanceFromStart * (totalDistanceMeters - distanceFromStart)) / + (2 * _earthRadiusMeters); + final refractedHeight = lineHeight + (unrefBulge - earthBulge); if (clearance < -obstructionToleranceMeters) { isClear = false; @@ -256,7 +276,7 @@ class LineOfSightService { distanceMeters: distanceFromStart, terrainMeters: terrainHeight, lineHeightMeters: lineHeight, - radioHorizonMeters: radioHorizonHeight, + refractedHeightMeters: refractedHeight, clearanceMeters: clearance, ), ); @@ -269,9 +289,20 @@ class LineOfSightService { maxObstructionMeters: maxObstructionMeters, firstObstructionDistanceMeters: firstObstructionDistanceMeters, samples: samples, + usedKFactor: kFactor, + frequencyMHz: frequencyMHz, ); } + static double _kFactorForFrequency(double? frequencyMHz) { + if (frequencyMHz == null) return _baselineKFactor; + final delta = + (frequencyMHz - _baselineFrequencyMHz) / _baselineFrequencyMHz; + final adjustment = delta * 0.15; + final scaled = _baselineKFactor * (1 + adjustment); + return scaled.clamp(1.1, 1.6).toDouble(); + } + List _buildSamplePoints( LatLng start, LatLng end, diff --git a/test/services/line_of_sight_service_test.dart b/test/services/line_of_sight_service_test.dart index 987ee6c..267a70b 100644 --- a/test/services/line_of_sight_service_test.dart +++ b/test/services/line_of_sight_service_test.dart @@ -16,6 +16,7 @@ void main() { elevations: elevations, startAntennaHeightMeters: 2, endAntennaHeightMeters: 2, + kFactor: 4.0 / 3.0, ); expect(result.hasData, isTrue); @@ -36,6 +37,7 @@ void main() { elevations: elevations, startAntennaHeightMeters: 1.5, endAntennaHeightMeters: 1.5, + kFactor: 4.0 / 3.0, ); expect(result.hasData, isTrue); From 677b25908ade7edc8b1e84487b74393be7e3388c Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 02:42:58 -0500 Subject: [PATCH 16/34] Document LOS frequency and k-factor math Show the connector frequency right next to the Frequency label, display the derived k value, and keep the info dialog tied to the exact --- lib/l10n/app_bg.arb | 18 +++++++- lib/l10n/app_de.arb | 18 +++++++- lib/l10n/app_en.arb | 16 +++++++ lib/l10n/app_es.arb | 18 +++++++- lib/l10n/app_fr.arb | 18 +++++++- lib/l10n/app_it.arb | 18 +++++++- lib/l10n/app_localizations.dart | 47 ++++++++++++++++++++ lib/l10n/app_localizations_bg.dart | 29 +++++++++++++ lib/l10n/app_localizations_de.dart | 28 ++++++++++++ lib/l10n/app_localizations_en.dart | 28 ++++++++++++ lib/l10n/app_localizations_es.dart | 28 ++++++++++++ lib/l10n/app_localizations_fr.dart | 28 ++++++++++++ lib/l10n/app_localizations_it.dart | 28 ++++++++++++ lib/l10n/app_localizations_nl.dart | 28 ++++++++++++ lib/l10n/app_localizations_pl.dart | 28 ++++++++++++ lib/l10n/app_localizations_pt.dart | 28 ++++++++++++ lib/l10n/app_localizations_ru.dart | 28 ++++++++++++ lib/l10n/app_localizations_sk.dart | 28 ++++++++++++ lib/l10n/app_localizations_sl.dart | 28 ++++++++++++ lib/l10n/app_localizations_sv.dart | 28 ++++++++++++ lib/l10n/app_localizations_uk.dart | 28 ++++++++++++ lib/l10n/app_localizations_zh.dart | 28 ++++++++++++ lib/l10n/app_nl.arb | 18 +++++++- lib/l10n/app_pl.arb | 18 +++++++- lib/l10n/app_pt.arb | 18 +++++++- lib/l10n/app_ru.arb | 18 +++++++- lib/l10n/app_sk.arb | 18 +++++++- lib/l10n/app_sl.arb | 18 +++++++- lib/l10n/app_sv.arb | 18 +++++++- lib/l10n/app_uk.arb | 18 +++++++- lib/l10n/app_zh.arb | 18 +++++++- lib/screens/line_of_sight_map_screen.dart | 52 +++++++++++------------ 32 files changed, 747 insertions(+), 41 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 8609023..dc0ca4e 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1716,5 +1716,21 @@ "losPointName": "Име на точката", "losShowPanelTooltip": "Показване на LOS панел", "losHidePanelTooltip": "Скриване на LOS панела", - "losElevationAttribution": "Данни за надморска височина: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e5c82f7..25c899c 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1744,5 +1744,21 @@ "losPointName": "Punktname", "losShowPanelTooltip": "LOS-Panel anzeigen", "losHidePanelTooltip": "LOS-Panel ausblenden", - "losElevationAttribution": "Höhendaten: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 67ca72e..3f89e48 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1665,6 +1665,22 @@ "losShowPanelTooltip": "Show LOS panel", "losHidePanelTooltip": "Hide LOS panel", "losElevationAttribution": "Elevation data: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Radio horizon", + "losLegendLosBeam": "LOS beam", + "losLegendTerrain": "Terrain", + "losFrequencyLabel": "Frequency", + "losFrequencyInfoTooltip": "View calculation details", + "losFrequencyDialogTitle": "Radio horizon calculation", + "losFrequencyDialogDescription": "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.", + "@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" } + } + }, "contacts_pathTrace": "Path Trace", "contacts_ping": "Ping", "contacts_repeaterPathTrace": "Path trace to repeater", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 483b4d3..0616454 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1744,5 +1744,21 @@ "losPointName": "Nombre del punto", "losShowPanelTooltip": "Mostrar panel LOS", "losHidePanelTooltip": "Ocultar panel LOS", - "losElevationAttribution": "Datos de elevación: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2d4846c..cfdd3ba 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1716,5 +1716,21 @@ "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)" + "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" } + } + } } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 2f8d186..427eb0a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1716,5 +1716,21 @@ "losPointName": "Nome del punto", "losShowPanelTooltip": "Mostra il pannello LOS", "losHidePanelTooltip": "Nascondi il pannello LOS", - "losElevationAttribution": "Dati di elevazione: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index e9686ce..015dcca 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -4992,6 +4992,53 @@ abstract class AppLocalizations { /// **'Elevation data: Open-Meteo (CC BY 4.0)'** String get losElevationAttribution; + /// No description provided for @losLegendRadioHorizon. + /// + /// In en, this message translates to: + /// **'Radio horizon'** + String get losLegendRadioHorizon; + + /// No description provided for @losLegendLosBeam. + /// + /// In en, this message translates to: + /// **'LOS beam'** + String get losLegendLosBeam; + + /// No description provided for @losLegendTerrain. + /// + /// In en, this message translates to: + /// **'Terrain'** + String get losLegendTerrain; + + /// No description provided for @losFrequencyLabel. + /// + /// In en, this message translates to: + /// **'Frequency'** + String get losFrequencyLabel; + + /// No description provided for @losFrequencyInfoTooltip. + /// + /// In en, this message translates to: + /// **'View calculation details'** + String get losFrequencyInfoTooltip; + + /// No description provided for @losFrequencyDialogTitle. + /// + /// In en, this message translates to: + /// **'Radio horizon calculation'** + String get losFrequencyDialogTitle; + + /// Explain how the calculation uses the baseline frequency and derived k-factor. + /// + /// In en, this message translates to: + /// **'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.'** + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double kFactor, + ); + /// No description provided for @contacts_pathTrace. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index cf4bf7b..68ed8e5 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2859,6 +2859,35 @@ class AppLocalizationsBg extends AppLocalizations { String get losElevationAttribution => 'Данни за надморска височина: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Радиохоризонт'; + + @override + String get losLegendLosBeam => 'LOS лъч'; + + @override + String get losLegendTerrain => 'Терен'; + + @override + String get losFrequencyLabel => 'Честота'; + + @override + String get losFrequencyInfoTooltip => + 'Преглед на подробностите за изчислението'; + + @override + String get losFrequencyDialogTitle => 'Изчисление на радиохоризонта'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double kFactor, + ) { + return 'Започвайки от k=$baselineK при $baselineFreq MHz, изчислението умножава 0.15 × (frequency − $baselineFreq) / $baselineFreq, за да достигне k approx $kFactor за текущата лента $frequencyMHz MHz, която определя извитата граница на радиохоризонта.'; + } + @override String get contacts_pathTrace => 'Пътен проследяване'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index c6a07a4..1c97a4c 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2865,6 +2865,34 @@ class AppLocalizationsDe extends AppLocalizations { @override String get losElevationAttribution => 'Höhendaten: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Funkhorizont'; + + @override + String get losLegendLosBeam => 'LOS-Strahl'; + + @override + String get losLegendTerrain => 'Gelände'; + + @override + String get losFrequencyLabel => 'Frequenz'; + + @override + String get losFrequencyInfoTooltip => 'Berechnungsdetails anzeigen'; + + @override + String get losFrequencyDialogTitle => 'Funkhorizont-Berechnung'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Pfadverfolgung'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 254b5f4..c5ef344 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2817,6 +2817,34 @@ class AppLocalizationsEn extends AppLocalizations { String get losElevationAttribution => 'Elevation data: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Radio horizon'; + + @override + String get losLegendLosBeam => 'LOS beam'; + + @override + String get losLegendTerrain => 'Terrain'; + + @override + String get losFrequencyLabel => 'Frequency'; + + @override + String get losFrequencyInfoTooltip => 'View calculation details'; + + @override + String get losFrequencyDialogTitle => 'Radio horizon calculation'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double 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 String get contacts_pathTrace => 'Path Trace'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index dcde365..33db872 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2859,6 +2859,34 @@ class AppLocalizationsEs extends AppLocalizations { String get losElevationAttribution => 'Datos de elevación: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Horizonte radioeléctrico'; + + @override + String get losLegendLosBeam => 'Haz LOS'; + + @override + String get losLegendTerrain => 'Terreno'; + + @override + String get losFrequencyLabel => 'Frecuencia'; + + @override + String get losFrequencyInfoTooltip => 'Ver detalles del cálculo'; + + @override + String get losFrequencyDialogTitle => 'Cálculo del horizonte radioeléctrico'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Rastreo de caminos'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index c4e1e27..fc059a9 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2874,6 +2874,34 @@ class AppLocalizationsFr extends AppLocalizations { String get losElevationAttribution => 'Données d\'altitude : Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Horizon radio'; + + @override + String get losLegendLosBeam => 'Faisceau LOS'; + + @override + String get losLegendTerrain => 'Terrain'; + + @override + String get losFrequencyLabel => 'Fréquence'; + + @override + String get losFrequencyInfoTooltip => 'Voir les détails du calcul'; + + @override + String get losFrequencyDialogTitle => 'Calcul de l’horizon radio'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Traçage de chemin'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index d8e27f8..123d194 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2859,6 +2859,34 @@ class AppLocalizationsIt extends AppLocalizations { String get losElevationAttribution => 'Dati di elevazione: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Orizzonte radio'; + + @override + String get losLegendLosBeam => 'Raggio LOS'; + + @override + String get losLegendTerrain => 'Terreno'; + + @override + String get losFrequencyLabel => 'Frequenza'; + + @override + String get losFrequencyInfoTooltip => 'Visualizza i dettagli del calcolo'; + + @override + String get losFrequencyDialogTitle => 'Calcolo dell’orizzonte radio'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Traccia Percorso'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 0a50e8b..3c6d5c4 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2850,6 +2850,34 @@ class AppLocalizationsNl extends AppLocalizations { String get losElevationAttribution => 'Hoogtegegevens: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Radiohorizon'; + + @override + String get losLegendLosBeam => 'LOS-straal'; + + @override + String get losLegendTerrain => 'Terrein'; + + @override + String get losFrequencyLabel => 'Frequentie'; + + @override + String get losFrequencyInfoTooltip => 'Berekeningsdetails bekijken'; + + @override + String get losFrequencyDialogTitle => 'Radiohorizon-berekening'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Pad Traceren'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 31dd8b5..02a6a11 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2856,6 +2856,34 @@ class AppLocalizationsPl extends AppLocalizations { String get losElevationAttribution => 'Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Horyzont radiowy'; + + @override + String get losLegendLosBeam => 'Wiązka LOS'; + + @override + String get losLegendTerrain => 'Teren'; + + @override + String get losFrequencyLabel => 'Częstotliwość'; + + @override + String get losFrequencyInfoTooltip => 'Zobacz szczegóły obliczeń'; + + @override + String get losFrequencyDialogTitle => 'Obliczanie horyzontu radiowego'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Śledzenie Ścieżek'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 5092826..7cb0986 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2858,6 +2858,34 @@ class AppLocalizationsPt extends AppLocalizations { String get losElevationAttribution => 'Dados de elevação: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Horizonte de rádio'; + + @override + String get losLegendLosBeam => 'Feixe LOS'; + + @override + String get losLegendTerrain => 'Terreno'; + + @override + String get losFrequencyLabel => 'Frequência'; + + @override + String get losFrequencyInfoTooltip => 'Ver detalhes do cálculo'; + + @override + String get losFrequencyDialogTitle => 'Cálculo do horizonte de rádio'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Traçado de Caminho'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 570b7c8..6e35b43 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2861,6 +2861,34 @@ class AppLocalizationsRu extends AppLocalizations { String get losElevationAttribution => 'Данные о высоте: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Радиогоризонт'; + + @override + String get losLegendLosBeam => 'Луч LOS'; + + @override + String get losLegendTerrain => 'Рельеф'; + + @override + String get losFrequencyLabel => 'Частота'; + + @override + String get losFrequencyInfoTooltip => 'Просмотреть детали расчёта'; + + @override + String get losFrequencyDialogTitle => 'Расчёт радиогоризонта'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double kFactor, + ) { + return 'Исходя из k=$baselineK при $baselineFreq MHz, расчёт умножает 0.15 × (frequency − $baselineFreq) / $baselineFreq, чтобы получить k approx $kFactor для текущего диапазона $frequencyMHz MHz, который определяет изогнутую границу радиогоризонта.'; + } + @override String get contacts_pathTrace => 'Трассировка пути'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 8bbb6de..041e7fd 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2844,6 +2844,34 @@ class AppLocalizationsSk extends AppLocalizations { String get losElevationAttribution => 'Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Rádiový horizont'; + + @override + String get losLegendLosBeam => 'LOS lúč'; + + @override + String get losLegendTerrain => 'Terén'; + + @override + String get losFrequencyLabel => 'Frekvencia'; + + @override + String get losFrequencyInfoTooltip => 'Zobraziť podrobnosti výpočtu'; + + @override + String get losFrequencyDialogTitle => 'Výpočet rádiového horizontu'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Sledovanie lúčov'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 61e3058..0a46533 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2847,6 +2847,34 @@ class AppLocalizationsSl extends AppLocalizations { String get losElevationAttribution => 'Podatki o višini: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Radijski horizont'; + + @override + String get losLegendLosBeam => 'LOS žarek'; + + @override + String get losLegendTerrain => 'Teren'; + + @override + String get losFrequencyLabel => 'Frekvenca'; + + @override + String get losFrequencyInfoTooltip => 'Prikaži podrobnosti izračuna'; + + @override + String get losFrequencyDialogTitle => 'Izračun radijskega horizonta'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Sledenje poti'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 79b30b8..0fb8e70 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2830,6 +2830,34 @@ class AppLocalizationsSv extends AppLocalizations { @override String get losElevationAttribution => 'Höjddata: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Radiohorisont'; + + @override + String get losLegendLosBeam => 'LOS-stråle'; + + @override + String get losLegendTerrain => 'Terräng'; + + @override + String get losFrequencyLabel => 'Frekvens'; + + @override + String get losFrequencyInfoTooltip => 'Visa beräkningsdetaljer'; + + @override + String get losFrequencyDialogTitle => 'Beräkning av radiohorisont'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + 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.'; + } + @override String get contacts_pathTrace => 'Path Trace'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index f367002..e81f8e1 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2869,6 +2869,34 @@ class AppLocalizationsUk extends AppLocalizations { String get losElevationAttribution => 'Дані про висоту: Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => 'Радіогоризонт'; + + @override + String get losLegendLosBeam => 'Промінь LOS'; + + @override + String get losLegendTerrain => 'Рельєф'; + + @override + String get losFrequencyLabel => 'Частота'; + + @override + String get losFrequencyInfoTooltip => 'Переглянути деталі розрахунку'; + + @override + String get losFrequencyDialogTitle => 'Розрахунок радіогоризонту'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double kFactor, + ) { + return 'Виходячи з k=$baselineK при $baselineFreq MHz, розрахунок множить 0.15 × (frequency − $baselineFreq) / $baselineFreq, щоб отримати k approx $kFactor для поточного діапазону $frequencyMHz MHz, який визначає вигнуту межу радіогоризонту.'; + } + @override String get contacts_pathTrace => 'Трасування шляхів'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 7641800..a7f4a8a 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2709,6 +2709,34 @@ class AppLocalizationsZh extends AppLocalizations { @override String get losElevationAttribution => '高程数据:Open-Meteo (CC BY 4.0)'; + @override + String get losLegendRadioHorizon => '无线电地平线'; + + @override + String get losLegendLosBeam => 'LOS 波束'; + + @override + String get losLegendTerrain => '地形'; + + @override + String get losFrequencyLabel => '频率'; + + @override + String get losFrequencyInfoTooltip => '查看计算详情'; + + @override + String get losFrequencyDialogTitle => '无线电地平线计算'; + + @override + String losFrequencyDialogDescription( + double baselineK, + double baselineFreq, + double frequencyMHz, + double kFactor, + ) { + return '从 k=$baselineK($baselineFreq MHz)开始,计算将 0.15 × (frequency − $baselineFreq) / $baselineFreq,以得到当前 $frequencyMHz MHz 频段的 k approx $kFactor,从而定义弯曲的无线电地平线边界。'; + } + @override String get contacts_pathTrace => '路径追踪'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 57b2fdd..3855e14 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1716,5 +1716,21 @@ "losPointName": "Puntnaam", "losShowPanelTooltip": "Toon LOS-paneel", "losHidePanelTooltip": "LOS-paneel verbergen", - "losElevationAttribution": "Hoogtegegevens: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 3787fa7..dde149c 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1716,5 +1716,21 @@ "losPointName": "Nazwa punktu", "losShowPanelTooltip": "Pokaż panel LOS", "losHidePanelTooltip": "Ukryj panel LOS", - "losElevationAttribution": "Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 7be6694..7edff74 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1716,5 +1716,21 @@ "losPointName": "Nome do ponto", "losShowPanelTooltip": "Mostrar painel LOS", "losHidePanelTooltip": "Ocultar painel LOS", - "losElevationAttribution": "Dados de elevação: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 26cfce3..139074b 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -956,5 +956,21 @@ "losPointName": "Имя точки", "losShowPanelTooltip": "Показать панель LOS", "losHidePanelTooltip": "Скрыть панель LOS", - "losElevationAttribution": "Данные о высоте: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 8b2cb0a..89a1b0d 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1716,5 +1716,21 @@ "losPointName": "Názov bodu", "losShowPanelTooltip": "Zobraziť panel LOS", "losHidePanelTooltip": "Skryť panel LOS", - "losElevationAttribution": "Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 4d3415d..2fe86e0 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1716,5 +1716,21 @@ "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)" + "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" } + } + } } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 8c5e399..2625fb2 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1716,5 +1716,21 @@ "losPointName": "Punktnamn", "losShowPanelTooltip": "Visa LOS-panelen", "losHidePanelTooltip": "Dölj LOS-panelen", - "losElevationAttribution": "Höjddata: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 910f8b0..8c28f19 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1716,5 +1716,21 @@ "losPointName": "Назва точки", "losShowPanelTooltip": "Показати панель LOS", "losHidePanelTooltip": "Приховати панель LOS", - "losElevationAttribution": "Дані про висоту: Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index d9efce7..bd8067f 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1716,5 +1716,21 @@ "losPointName": "点名称", "losShowPanelTooltip": "显示 LOS 面板", "losHidePanelTooltip": "隐藏 LOS 面板", - "losElevationAttribution": "高程数据:Open-Meteo (CC BY 4.0)" + "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" } + } + } } diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 5eb532b..72c2232 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -471,6 +471,9 @@ class _LineOfSightMapScreenState extends State { fontSize: 10, fontWeight: FontWeight.w600, ), + terrainLabel: context.l10n.losLegendTerrain, + losBeamLabel: context.l10n.losLegendLosBeam, + radioHorizonLabel: context.l10n.losLegendRadioHorizon, ), ), ) @@ -504,7 +507,7 @@ class _LineOfSightMapScreenState extends State { child: Row( children: [ Text( - 'Frequency', + context.l10n.losFrequencyLabel, style: TextStyle( fontSize: 11, color: Colors.grey[700], @@ -531,7 +534,7 @@ class _LineOfSightMapScreenState extends State { constraints: const BoxConstraints(), icon: const Icon(Icons.info_outline, size: 16), color: Colors.grey[600], - tooltip: 'View calculation details', + tooltip: context.l10n.losFrequencyInfoTooltip, onPressed: () { _showFrequencyInfoDialog( context, @@ -963,27 +966,13 @@ class _LineOfSightMapScreenState extends State { showDialog( context: context, builder: (dialogContext) => AlertDialog( - title: const Text('Radio horizon calculation'), - content: Text.rich( - TextSpan( - children: [ - TextSpan( - text: - 'Starting from k=$baselineK at ${baselineFreq.toStringAsFixed(3)} MHz, ', - ), - const TextSpan(text: 'the calculation multiplies the offset by '), - TextSpan( - text: - '0.15 × (frequency − ${baselineFreq.toStringAsFixed(3)}) / ${baselineFreq.toStringAsFixed(3)} ', - ), - TextSpan( - text: - 'to get k ≈ ${kFactor.toStringAsFixed(3)} for the current ${frequencyMHz.toStringAsFixed(3)} MHz band, ', - ), - const TextSpan( - text: 'which defines the curved radio horizon cap.', - ), - ], + title: Text(context.l10n.losFrequencyDialogTitle), + content: Text( + context.l10n.losFrequencyDialogDescription( + baselineK, + baselineFreq, + frequencyMHz, + kFactor, ), ), actions: [ @@ -1009,12 +998,18 @@ class _LosProfilePainter extends CustomPainter { final String distanceUnit; final String heightUnit; final TextStyle badgeTextStyle; + final String terrainLabel; + final String losBeamLabel; + final String radioHorizonLabel; const _LosProfilePainter({ required this.samples, required this.distanceUnit, required this.heightUnit, required this.badgeTextStyle, + required this.terrainLabel, + required this.losBeamLabel, + required this.radioHorizonLabel, }); @override @@ -1148,7 +1143,10 @@ class _LosProfilePainter extends CustomPainter { return oldDelegate.samples != samples || oldDelegate.distanceUnit != distanceUnit || oldDelegate.heightUnit != heightUnit || - oldDelegate.badgeTextStyle != badgeTextStyle; + oldDelegate.badgeTextStyle != badgeTextStyle || + oldDelegate.terrainLabel != terrainLabel || + oldDelegate.losBeamLabel != losBeamLabel || + oldDelegate.radioHorizonLabel != radioHorizonLabel; } void _drawUnitBadge(Canvas canvas, Size size) { @@ -1175,9 +1173,9 @@ class _LosProfilePainter extends CustomPainter { const legendPadding = 6.0; final entries = [ - _LegendEntry('Terrain', terrainColor), - _LegendEntry('LOS beam', losColor), - _LegendEntry('Radio horizon', horizonColor), + _LegendEntry(terrainLabel, terrainColor), + _LegendEntry(losBeamLabel, losColor), + _LegendEntry(radioHorizonLabel, horizonColor), ]; final textStyle = badgeTextStyle.copyWith( From 16b2c249830aa5692b7decc82980a4990cb3dcd4 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 12:18:42 -0500 Subject: [PATCH 17/34] Propagate LOS frequency data and clamp bounds --- lib/screens/line_of_sight_map_screen.dart | 14 ++++++-- lib/services/line_of_sight_service.dart | 1 + pubspec.lock | 42 ++++++++++++++++++++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 72c2232..c3fe476 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -1021,10 +1021,20 @@ class _LosProfilePainter extends CustomPainter { if (samples.length < 2) return; final minY = samples - .map((s) => math.min(s.terrainMeters, s.lineHeightMeters)) + .map( + (s) => math.min( + math.min(s.terrainMeters, s.lineHeightMeters), + s.refractedHeightMeters, + ), + ) .reduce(math.min); final maxY = samples - .map((s) => math.max(s.terrainMeters, s.lineHeightMeters)) + .map( + (s) => math.max( + math.max(s.terrainMeters, s.lineHeightMeters), + s.refractedHeightMeters, + ), + ) .reduce(math.max); final ySpan = math.max(1.0, maxY - minY); final maxDist = math.max(1.0, samples.last.distanceMeters); diff --git a/lib/services/line_of_sight_service.dart b/lib/services/line_of_sight_service.dart index 14d8fc6..61e9e27 100644 --- a/lib/services/line_of_sight_service.dart +++ b/lib/services/line_of_sight_service.dart @@ -212,6 +212,7 @@ class LineOfSightService { startAntennaHeightMeters: startAntennaHeightMeters, endAntennaHeightMeters: endAntennaHeightMeters, kFactor: kFactor, + frequencyMHz: frequencyMHz, obstructionToleranceMeters: obstructionToleranceMeters, ); } diff --git a/pubspec.lock b/pubspec.lock index ed84c40..22cad80 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -347,6 +347,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.2.2" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" + url: "https://pub.dev" + source: hosted + version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -597,6 +605,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -1010,6 +1026,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + url: "https://pub.dev" + source: hosted + version: "1.2.0" vector_math: dependency: transitive description: @@ -1043,7 +1083,7 @@ packages: source: hosted version: "1.3.0" web: - dependency: transitive + dependency: "direct main" description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" From c0516a475d24bbc6391470b74b3b0994713023b9 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:36:10 -0500 Subject: [PATCH 18/34] fix: extend los profile edges --- lib/screens/line_of_sight_map_screen.dart | 219 +++++++++++++--------- 1 file changed, 129 insertions(+), 90 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index c3fe476..785dfe5 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -487,6 +487,14 @@ class _LineOfSightMapScreenState extends State { ), ), ), + if (segment != null) ...[ + const SizedBox(height: 8), + _LosLegend( + terrainLabel: context.l10n.losLegendTerrain, + losBeamLabel: context.l10n.losLegendLosBeam, + radioHorizonLabel: context.l10n.losLegendRadioHorizon, + ), + ], const SizedBox(height: 8), Text( segment != null @@ -1038,36 +1046,85 @@ class _LosProfilePainter extends CustomPainter { .reduce(math.max); final ySpan = math.max(1.0, maxY - minY); final maxDist = math.max(1.0, samples.last.distanceMeters); + const horizontalPadding = 12.0; + const verticalPadding = 12.0; + final chartWidth = math.max(1.0, size.width - horizontalPadding * 2); + final chartHeight = math.max(1.0, size.height - verticalPadding * 2); Offset mapPoint(double x, double y) { - final px = (x / maxDist) * size.width; - final py = size.height - ((y - minY) / ySpan) * size.height; + final px = horizontalPadding + (x / maxDist) * chartWidth; + final py = + size.height - verticalPadding - ((y - minY) / ySpan) * chartHeight; return Offset(px, py); } - final terrainPath = ui.Path(); - terrainPath.moveTo(0, size.height); - for (final s in samples) { - final p = mapPoint(s.distanceMeters, s.terrainMeters); + final firstTerrainPoint = mapPoint( + samples.first.distanceMeters, + samples.first.terrainMeters, + ); + final lastTerrainPoint = mapPoint( + samples.last.distanceMeters, + samples.last.terrainMeters, + ); + + double distanceForCanvasX(double x) => + ((x - horizontalPadding) / chartWidth) * maxDist; + + double elevationToPixel(double elevation) => + size.height - + verticalPadding - + ((elevation - minY) / ySpan) * chartHeight; + + double extrapolateTerrain(double distance, bool isLeft) { + final samplesForSlope = isLeft + ? samples.sublist(0, math.min(2, samples.length)) + : samples.sublist(samples.length - math.min(2, samples.length)); + if (samplesForSlope.length < 2) { + return samplesForSlope.first.terrainMeters; + } + final a = samplesForSlope.first; + final b = samplesForSlope.last; + final dx = b.distanceMeters - a.distanceMeters; + if (dx.abs() < 1e-6) return a.terrainMeters; + final slope = (b.terrainMeters - a.terrainMeters) / dx; + return a.terrainMeters + slope * (distance - a.distanceMeters); + } + + final leftDistance = distanceForCanvasX(0.0); + final rightDistance = distanceForCanvasX(size.width); + final leftEdgeTerrain = extrapolateTerrain(leftDistance, true); + final rightEdgeTerrain = extrapolateTerrain(rightDistance, false); + final leftEdgePoint = Offset(0.0, elevationToPixel(leftEdgeTerrain)); + final rightEdgePoint = Offset( + size.width, + elevationToPixel(rightEdgeTerrain), + ); + + final terrainPath = ui.Path() + ..moveTo(0, size.height) + ..lineTo(leftEdgePoint.dx, leftEdgePoint.dy) + ..lineTo(firstTerrainPoint.dx, firstTerrainPoint.dy); + for (final sample in samples) { + final p = mapPoint(sample.distanceMeters, sample.terrainMeters); terrainPath.lineTo(p.dx, p.dy); } - terrainPath.lineTo(size.width, size.height); - terrainPath.close(); + terrainPath + ..lineTo(lastTerrainPoint.dx, lastTerrainPoint.dy) + ..lineTo(rightEdgePoint.dx, rightEdgePoint.dy) + ..lineTo(size.width, size.height) + ..close(); const terrainFillColor = Color(0xCC7C6F5D); const terrainLineColor = Color(0xFF9FE870); const losLineColor = Color(0xFFE0E7FF); canvas.drawPath(terrainPath, Paint()..color = terrainFillColor); - final terrainLine = ui.Path(); - for (int i = 0; i < samples.length; i++) { - final p = mapPoint(samples[i].distanceMeters, samples[i].terrainMeters); - if (i == 0) { - terrainLine.moveTo(p.dx, p.dy); - } else { - terrainLine.lineTo(p.dx, p.dy); - } + final terrainLine = ui.Path()..moveTo(leftEdgePoint.dx, leftEdgePoint.dy); + for (final sample in samples) { + final p = mapPoint(sample.distanceMeters, sample.terrainMeters); + terrainLine.lineTo(p.dx, p.dy); } + terrainLine.lineTo(rightEdgePoint.dx, rightEdgePoint.dy); canvas.drawPath( terrainLine, Paint() @@ -1144,8 +1201,6 @@ class _LosProfilePainter extends CustomPainter { ..color = horizonFillColor ..style = PaintingStyle.fill, ); - - _drawLegend(canvas, refractedLineColor, losLineColor, terrainLineColor); } @override @@ -1168,84 +1223,68 @@ class _LosProfilePainter extends CustomPainter { ..layout(); painter.paint(canvas, Offset(size.width - painter.width - 8, 8)); } +} - void _drawLegend( - Canvas canvas, - Color horizonColor, - Color losColor, - Color terrainColor, - ) { - const legendX = 8.0; - const legendY = 8.0; - const swatchSize = 10.0; - const swatchTextGap = 6.0; - const entrySpacing = 4.0; - const legendPadding = 6.0; +class _LosLegend extends StatelessWidget { + static const _terrainColor = Color(0xFF9FE870); + static const _losColor = Color(0xFFE0E7FF); + static const _radioColor = Color(0xFFFFD57F); + + final String terrainLabel; + final String losBeamLabel; + final String radioHorizonLabel; + + const _LosLegend({ + required this.terrainLabel, + required this.losBeamLabel, + required this.radioHorizonLabel, + }); + + @override + Widget build(BuildContext context) { + final textStyle = + Theme.of(context).textTheme.labelSmall?.copyWith( + color: Colors.white70, + fontSize: 11, + fontWeight: FontWeight.w500, + ) ?? + const TextStyle( + color: Colors.white70, + fontSize: 11, + fontWeight: FontWeight.w500, + ); final entries = [ - _LegendEntry(terrainLabel, terrainColor), - _LegendEntry(losBeamLabel, losColor), - _LegendEntry(radioHorizonLabel, horizonColor), + _LegendEntry(terrainLabel, _terrainColor), + _LegendEntry(losBeamLabel, _losColor), + _LegendEntry(radioHorizonLabel, _radioColor), ]; - final textStyle = badgeTextStyle.copyWith( - fontSize: 10, - fontWeight: FontWeight.w500, + const swatchSize = 10.0; + + return Wrap( + spacing: 16, + runSpacing: 6, + children: entries + .map( + (entry) => Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: swatchSize, + height: swatchSize, + decoration: BoxDecoration( + color: entry.color, + borderRadius: BorderRadius.circular(2), + ), + ), + const SizedBox(width: 6), + Text(entry.label, style: textStyle), + ], + ), + ) + .toList(), ); - - final painters = entries.map((entry) { - final painter = TextPainter( - text: TextSpan(text: entry.label, style: textStyle), - textDirection: TextDirection.ltr, - )..layout(); - return painter; - }).toList(); - - final maxTextWidth = painters.map((p) => p.width).fold(0, math.max); - - final legendWidth = - legendPadding * 2 + swatchSize + swatchTextGap + maxTextWidth; - - final legendHeight = - legendPadding * 2 + - entries.length * swatchSize + - (entries.length - 1) * entrySpacing; - - final legendRect = RRect.fromLTRBR( - legendX, - legendY, - legendX + legendWidth, - legendY + legendHeight, - const Radius.circular(10), - ); - - canvas.drawRRect( - legendRect, - Paint()..color = const Color.fromARGB(90, 0, 0, 0), - ); - - var yOffset = legendY + legendPadding; - for (int i = 0; i < entries.length; i++) { - final entry = entries[i]; - final painter = painters[i]; - final swatchRect = Rect.fromLTWH( - legendX + legendPadding, - yOffset, - swatchSize, - swatchSize, - ); - canvas.drawRect(swatchRect, Paint()..color = entry.color); - - painter.paint( - canvas, - Offset( - swatchRect.right + swatchTextGap, - yOffset + (swatchSize - painter.height) / 2, - ), - ); - - yOffset += swatchSize + entrySpacing; - } } } From ec14870aeda7607b2d097224922c23b85e195474 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:42:30 -0500 Subject: [PATCH 19/34] Update after upstream merged other commits --- lib/l10n/app_bg.arb | 20 +++- lib/l10n/app_de.arb | 20 +++- lib/l10n/app_es.arb | 20 +++- lib/l10n/app_fr.arb | 20 +++- lib/l10n/app_it.arb | 20 +++- lib/l10n/app_localizations_bg.dart | 14 +-- lib/l10n/app_localizations_de.dart | 14 +-- lib/l10n/app_localizations_es.dart | 14 +-- lib/l10n/app_localizations_fr.dart | 14 +-- lib/l10n/app_localizations_it.dart | 14 +-- lib/l10n/app_localizations_nl.dart | 14 +-- lib/l10n/app_localizations_pl.dart | 14 +-- lib/l10n/app_localizations_pt.dart | 14 +-- lib/l10n/app_localizations_ru.dart | 14 +-- lib/l10n/app_localizations_sk.dart | 14 +-- lib/l10n/app_localizations_sl.dart | 14 +-- lib/l10n/app_localizations_sv.dart | 14 +-- lib/l10n/app_localizations_uk.dart | 14 +-- lib/l10n/app_localizations_zh.dart | 14 +-- lib/l10n/app_nl.arb | 20 +++- lib/l10n/app_pl.arb | 20 +++- lib/l10n/app_pt.arb | 20 +++- lib/l10n/app_ru.arb | 20 +++- lib/l10n/app_sk.arb | 20 +++- lib/l10n/app_sl.arb | 20 +++- lib/l10n/app_sv.arb | 20 +++- lib/l10n/app_uk.arb | 20 +++- lib/l10n/app_zh.arb | 20 +++- untranslated.json | 142 +---------------------------- 29 files changed, 351 insertions(+), 267 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index e9f46c6..c245101 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1718,5 +1718,21 @@ "losPointName": "Име на точката", "losShowPanelTooltip": "Показване на LOS панел", "losHidePanelTooltip": "Скриване на LOS панела", - "losElevationAttribution": "Данни за надморска височина: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Данни за надморска височина: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Радиохоризонт", + "losLegendLosBeam": "Линия на видимост", + "losLegendTerrain": "Терен", + "losFrequencyLabel": "Честота", + "losFrequencyInfoTooltip": "Преглед на детайли за изчислението", + "losFrequencyDialogTitle": "Изчисляване на радиохоризонта", + "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {baselineFreq} MHz, изчислението умножава 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, за да достигне k приблизително {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" } + } + } +} diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index bdea574..1f67898 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1746,5 +1746,21 @@ "losPointName": "Punktname", "losShowPanelTooltip": "LOS-Panel anzeigen", "losHidePanelTooltip": "LOS-Panel ausblenden", - "losElevationAttribution": "Höhendaten: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Höhendaten: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Funkhorizont", + "losLegendLosBeam": "Sichtlinie", + "losLegendTerrain": "Gelände", + "losFrequencyLabel": "Frequenz", + "losFrequencyInfoTooltip": "Details zur Berechnung anzeigen", + "losFrequencyDialogTitle": "Berechnung des Funkhorizonts", + "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {baselineFreq} MHz multipliziert die Berechnung 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, um k etwa {kFactor} für das aktuelle Band {frequencyMHz} MHz zu erreichen, was die gekrümmte Funkhorizont-Begrenzung 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" } + } + } +} diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 99db15d..9721f6b 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1746,5 +1746,21 @@ "losPointName": "Nombre del punto", "losShowPanelTooltip": "Mostrar panel LOS", "losHidePanelTooltip": "Ocultar panel LOS", - "losElevationAttribution": "Datos de elevación: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Datos de elevación: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Horizonte radioeléctrico", + "losLegendLosBeam": "Línea de visión", + "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 alcanzar k aprox {kFactor} para la banda actual {frequencyMHz} MHz, lo 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" } + } + } +} diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index bc82195..c6d5de3 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1718,5 +1718,21 @@ "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)" -} \ No newline at end of file + "losElevationAttribution": "Données d’altitude : Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Horizon radio", + "losLegendLosBeam": "Ligne de visée", + "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 env {kFactor} pour la bande actuelle {frequencyMHz} MHz, ce 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" } + } + } +} diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index fe4bffc..a51cb6b 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1718,5 +1718,21 @@ "losPointName": "Nome del punto", "losShowPanelTooltip": "Mostra il pannello LOS", "losHidePanelTooltip": "Nascondi il pannello LOS", - "losElevationAttribution": "Dati di elevazione: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Dati di elevazione: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Orizzonte radio", + "losLegendLosBeam": "Linea di vista", + "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 circa {kFactor} per la banda corrente {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" } + } + } +} diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 7da0714..52c4246 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2868,22 +2868,22 @@ class AppLocalizationsBg extends AppLocalizations { 'Данни за надморска височина: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Радиохоризонт'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Линия на видимост'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Терен'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Честота'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Преглед на детайли за изчислението'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Изчисляване на радиохоризонта'; @override String losFrequencyDialogDescription( @@ -2892,7 +2892,7 @@ class AppLocalizationsBg extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Започвайки от k=$baselineK при $baselineFreq MHz, изчислението умножава 0.15 × (frequency − $baselineFreq) / $baselineFreq, за да достигне k приблизително $kFactor за текущата лента $frequencyMHz MHz, което определя извитата граница на радиохоризонта.'; } @override diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index b81565c..e5eb247 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2874,22 +2874,22 @@ class AppLocalizationsDe extends AppLocalizations { String get losElevationAttribution => 'Höhendaten: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Funkhorizont'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Sichtlinie'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Gelände'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frequenz'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Details zur Berechnung anzeigen'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Berechnung des Funkhorizonts'; @override String losFrequencyDialogDescription( @@ -2898,7 +2898,7 @@ class AppLocalizationsDe extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Ausgehend von k=$baselineK bei $baselineFreq MHz multipliziert die Berechnung 0.15 × (frequency − $baselineFreq) / $baselineFreq, um k etwa $kFactor für das aktuelle Band $frequencyMHz MHz zu erreichen, was die gekrümmte Funkhorizont-Begrenzung definiert.'; } @override diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 971d9d3..f411b18 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2868,22 +2868,22 @@ class AppLocalizationsEs extends AppLocalizations { 'Datos de elevación: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Horizonte radioeléctrico'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Línea de visión'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terreno'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frecuencia'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Ver detalles del cálculo'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Cálculo del horizonte radioeléctrico'; @override String losFrequencyDialogDescription( @@ -2892,7 +2892,7 @@ class AppLocalizationsEs extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Partiendo de k=$baselineK a $baselineFreq MHz, el cálculo multiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq para alcanzar k aprox $kFactor para la banda actual $frequencyMHz MHz, lo que define el límite curvo del horizonte radioeléctrico.'; } @override diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 1627987..2269ea1 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2880,25 +2880,25 @@ class AppLocalizationsFr extends AppLocalizations { @override String get losElevationAttribution => - 'Données d\'altitude : Open-Meteo (CC BY 4.0)'; + 'Données d’altitude : Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Horizon radio'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Ligne de visée'; @override String get losLegendTerrain => 'Terrain'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Fréquence'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Voir les détails du calcul'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Calcul de l’horizon radio'; @override String losFrequencyDialogDescription( @@ -2907,7 +2907,7 @@ class AppLocalizationsFr extends AppLocalizations { double frequencyMHz, double 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.'; + return 'En partant de k=$baselineK à $baselineFreq MHz, le calcul multiplie 0.15 × (frequency − $baselineFreq) / $baselineFreq pour atteindre k env $kFactor pour la bande actuelle $frequencyMHz MHz, ce qui définit la limite courbe de l’horizon radio.'; } @override diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index dccc31a..91d7c35 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2868,22 +2868,22 @@ class AppLocalizationsIt extends AppLocalizations { 'Dati di elevazione: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Orizzonte radio'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Linea di vista'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terreno'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frequenza'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Visualizza i dettagli del calcolo'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Calcolo dell’orizzonte radio'; @override String losFrequencyDialogDescription( @@ -2892,7 +2892,7 @@ class AppLocalizationsIt extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Partendo da k=$baselineK a $baselineFreq MHz, il calcolo moltiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq per raggiungere k circa $kFactor per la banda corrente $frequencyMHz MHz, che definisce il limite curvo dell’orizzonte radio.'; } @override diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index b02ffa7..8e03b53 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2858,22 +2858,22 @@ class AppLocalizationsNl extends AppLocalizations { 'Hoogtegegevens: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Radiohorizon'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Zichtlijn'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terrein'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frequentie'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Bekijk details van de berekening'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Berekening van de radiohorizon'; @override String losFrequencyDialogDescription( @@ -2882,7 +2882,7 @@ class AppLocalizationsNl extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Uitgaande van k=$baselineK bij $baselineFreq MHz vermenigvuldigt de berekening 0.15 × (frequency − $baselineFreq) / $baselineFreq om k ongeveer $kFactor te bereiken voor de huidige band $frequencyMHz MHz, wat de gebogen radiohorizon-grens definieert.'; } @override diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index b8e2705..29bbbc4 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2864,22 +2864,22 @@ class AppLocalizationsPl extends AppLocalizations { 'Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Horyzont radiowy'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Linia widoczności'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Teren'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Częstotliwość'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Zobacz szczegóły obliczenia'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Obliczanie horyzontu radiowego'; @override String losFrequencyDialogDescription( @@ -2888,7 +2888,7 @@ class AppLocalizationsPl extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Zaczynając od k=$baselineK przy $baselineFreq MHz, obliczenie mnoży 0.15 × (frequency − $baselineFreq) / $baselineFreq, aby osiągnąć k około $kFactor dla bieżącego pasma $frequencyMHz MHz, co definiuje zakrzywioną granicę horyzontu radiowego.'; } @override diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index b492c33..e3673f5 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2867,22 +2867,22 @@ class AppLocalizationsPt extends AppLocalizations { 'Dados de elevação: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Horizonte de rádio'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Linha de visada'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terreno'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frequência'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Ver detalhes do cálculo'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Cálculo do horizonte de rádio'; @override String losFrequencyDialogDescription( @@ -2891,7 +2891,7 @@ class AppLocalizationsPt extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Partindo de k=$baselineK a $baselineFreq MHz, o cálculo multiplica 0.15 × (frequency − $baselineFreq) / $baselineFreq para atingir k aprox $kFactor para a banda atual $frequencyMHz MHz, o que define o limite curvo do horizonte de rádio.'; } @override diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 383bf09..44ccf7c 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2870,22 +2870,22 @@ class AppLocalizationsRu extends AppLocalizations { 'Данные о высоте: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Радиогоризонт'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Линия прямой видимости'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Рельеф'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Частота'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Просмотреть детали расчёта'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Расчёт радиогоризонта'; @override String losFrequencyDialogDescription( @@ -2894,7 +2894,7 @@ class AppLocalizationsRu extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Начиная с k=$baselineK при $baselineFreq MHz, расчёт умножает 0.15 × (frequency − $baselineFreq) / $baselineFreq, чтобы получить k примерно $kFactor для текущего диапазона $frequencyMHz MHz, что определяет изогнутую границу радиогоризонта.'; } @override diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 474cf32..39c277b 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2852,22 +2852,22 @@ class AppLocalizationsSk extends AppLocalizations { 'Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Rádiový horizont'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Priama viditeľnosť'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terén'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frekvencia'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Zobraziť podrobnosti výpočtu'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Výpočet rádiového horizontu'; @override String losFrequencyDialogDescription( @@ -2876,7 +2876,7 @@ class AppLocalizationsSk extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Vychádzajúc z k=$baselineK pri $baselineFreq MHz výpočet násobí 0.15 × (frequency − $baselineFreq) / $baselineFreq, aby dosiahol k približne $kFactor pre aktuálne pásmo $frequencyMHz MHz, čo definuje zakrivenú hranicu rádiového horizontu.'; } @override diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 6662bc1..db973e8 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2855,22 +2855,22 @@ class AppLocalizationsSl extends AppLocalizations { 'Podatki o višini: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Radijski horizont'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Linija vidnosti'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Teren'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frekvenca'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Prikaži podrobnosti izračuna'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Izračun radijskega horizonta'; @override String losFrequencyDialogDescription( @@ -2879,7 +2879,7 @@ class AppLocalizationsSl extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Začenši z k=$baselineK pri $baselineFreq MHz izračun množi 0.15 × (frequency − $baselineFreq) / $baselineFreq, da doseže k približno $kFactor za trenutni pas $frequencyMHz MHz, kar določa ukrivljeno mejo radijskega horizonta.'; } @override diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 35a532b..8a3f29f 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2838,22 +2838,22 @@ class AppLocalizationsSv extends AppLocalizations { String get losElevationAttribution => 'Höjddata: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Radiohorisont'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Siktlinje'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Terräng'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Frekvens'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Visa detaljer om beräkningen'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Beräkning av radiohorisonten'; @override String losFrequencyDialogDescription( @@ -2862,7 +2862,7 @@ class AppLocalizationsSv extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Med utgångspunkt från k=$baselineK vid $baselineFreq MHz multiplicerar beräkningen 0.15 × (frequency − $baselineFreq) / $baselineFreq för att nå k cirka $kFactor för det aktuella bandet $frequencyMHz MHz, vilket definierar den krökta radiohorisontgränsen.'; } @override diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 4e7130b..1d38ca0 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2878,22 +2878,22 @@ class AppLocalizationsUk extends AppLocalizations { 'Дані про висоту: Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => 'Радіогоризонт'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => 'Лінія прямої видимості'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => 'Рельєф'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => 'Частота'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => 'Переглянути деталі розрахунку'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => 'Розрахунок радіогоризонту'; @override String losFrequencyDialogDescription( @@ -2902,7 +2902,7 @@ class AppLocalizationsUk extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Починаючи з k=$baselineK при $baselineFreq MHz, розрахунок множить 0.15 × (frequency − $baselineFreq) / $baselineFreq, щоб досягти k приблизно $kFactor для поточного діапазону $frequencyMHz MHz, що визначає вигнуту межу радіогоризонту.'; } @override diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 2ecf38e..fa1a34a 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2716,22 +2716,22 @@ class AppLocalizationsZh extends AppLocalizations { String get losElevationAttribution => '高程数据:Open-Meteo (CC BY 4.0)'; @override - String get losLegendRadioHorizon => 'Radio horizon'; + String get losLegendRadioHorizon => '无线电地平线'; @override - String get losLegendLosBeam => 'LOS beam'; + String get losLegendLosBeam => '视距波束'; @override - String get losLegendTerrain => 'Terrain'; + String get losLegendTerrain => '地形'; @override - String get losFrequencyLabel => 'Frequency'; + String get losFrequencyLabel => '频率'; @override - String get losFrequencyInfoTooltip => 'View calculation details'; + String get losFrequencyInfoTooltip => '查看计算详情'; @override - String get losFrequencyDialogTitle => 'Radio horizon calculation'; + String get losFrequencyDialogTitle => '无线电地平线计算'; @override String losFrequencyDialogDescription( @@ -2740,7 +2740,7 @@ class AppLocalizationsZh extends AppLocalizations { double frequencyMHz, double 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.'; + return '从 $baselineFreq MHz 的 k=$baselineK 开始,计算将 0.15 × (frequency − $baselineFreq) / $baselineFreq 相乘,以在当前频段 $frequencyMHz MHz 下得到约 k=$kFactor,从而定义弯曲的无线电地平线边界。'; } @override diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 2f39fdf..f47a3b9 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1718,5 +1718,21 @@ "losPointName": "Puntnaam", "losShowPanelTooltip": "Toon LOS-paneel", "losHidePanelTooltip": "LOS-paneel verbergen", - "losElevationAttribution": "Hoogtegegevens: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Hoogtegegevens: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Radiohorizon", + "losLegendLosBeam": "Zichtlijn", + "losLegendTerrain": "Terrein", + "losFrequencyLabel": "Frequentie", + "losFrequencyInfoTooltip": "Bekijk details van de berekening", + "losFrequencyDialogTitle": "Berekening van de radiohorizon", + "losFrequencyDialogDescription": "Uitgaande van k={baselineK} bij {baselineFreq} MHz vermenigvuldigt de berekening 0.15 × (frequency − {baselineFreq}) / {baselineFreq} om k ongeveer {kFactor} te bereiken voor de huidige band {frequencyMHz} MHz, wat de gebogen radiohorizon-grens 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" } + } + } +} diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 0432f8f..3b56900 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1718,5 +1718,21 @@ "losPointName": "Nazwa punktu", "losShowPanelTooltip": "Pokaż panel LOS", "losHidePanelTooltip": "Ukryj panel LOS", - "losElevationAttribution": "Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Dane dotyczące wysokości: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Horyzont radiowy", + "losLegendLosBeam": "Linia widoczności", + "losLegendTerrain": "Teren", + "losFrequencyLabel": "Częstotliwość", + "losFrequencyInfoTooltip": "Zobacz szczegóły obliczenia", + "losFrequencyDialogTitle": "Obliczanie horyzontu radiowego", + "losFrequencyDialogDescription": "Zaczynając od k={baselineK} przy {baselineFreq} MHz, obliczenie mnoży 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, aby osiągnąć k około {kFactor} dla bieżącego pasma {frequencyMHz} MHz, co 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" } + } + } +} diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 01c5a83..a058bff 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1718,5 +1718,21 @@ "losPointName": "Nome do ponto", "losShowPanelTooltip": "Mostrar painel LOS", "losHidePanelTooltip": "Ocultar painel LOS", - "losElevationAttribution": "Dados de elevação: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Dados de elevação: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Horizonte de rádio", + "losLegendLosBeam": "Linha de visada", + "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 atingir k aprox {kFactor} para a banda atual {frequencyMHz} MHz, o 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" } + } + } +} diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index b8a20d9..f439754 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -958,5 +958,21 @@ "losPointName": "Имя точки", "losShowPanelTooltip": "Показать панель LOS", "losHidePanelTooltip": "Скрыть панель LOS", - "losElevationAttribution": "Данные о высоте: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Данные о высоте: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Радиогоризонт", + "losLegendLosBeam": "Линия прямой видимости", + "losLegendTerrain": "Рельеф", + "losFrequencyLabel": "Частота", + "losFrequencyInfoTooltip": "Просмотреть детали расчёта", + "losFrequencyDialogTitle": "Расчёт радиогоризонта", + "losFrequencyDialogDescription": "Начиная с k={baselineK} при {baselineFreq} MHz, расчёт умножает 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, чтобы получить k примерно {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" } + } + } +} diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 3245282..0801b8d 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1718,5 +1718,21 @@ "losPointName": "Názov bodu", "losShowPanelTooltip": "Zobraziť panel LOS", "losHidePanelTooltip": "Skryť panel LOS", - "losElevationAttribution": "Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Údaje o nadmorskej výške: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Rádiový horizont", + "losLegendLosBeam": "Priama viditeľnosť", + "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 približne {kFactor} pre aktuálne pásmo {frequencyMHz} MHz, čo 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" } + } + } +} diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index c560c31..d7e9ab3 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1718,5 +1718,21 @@ "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)" -} \ No newline at end of file + "losElevationAttribution": "Podatki o višini: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Radijski horizont", + "losLegendLosBeam": "Linija vidnosti", + "losLegendTerrain": "Teren", + "losFrequencyLabel": "Frekvenca", + "losFrequencyInfoTooltip": "Prikaži podrobnosti izračuna", + "losFrequencyDialogTitle": "Izračun radijskega horizonta", + "losFrequencyDialogDescription": "Začenši z k={baselineK} pri {baselineFreq} MHz izračun množi 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, da doseže k približno {kFactor} za trenutni pas {frequencyMHz} MHz, kar 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" } + } + } +} diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index b93c5ca..dcb4069 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1718,5 +1718,21 @@ "losPointName": "Punktnamn", "losShowPanelTooltip": "Visa LOS-panelen", "losHidePanelTooltip": "Dölj LOS-panelen", - "losElevationAttribution": "Höjddata: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Höjddata: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Radiohorisont", + "losLegendLosBeam": "Siktlinje", + "losLegendTerrain": "Terräng", + "losFrequencyLabel": "Frekvens", + "losFrequencyInfoTooltip": "Visa detaljer om beräkningen", + "losFrequencyDialogTitle": "Beräkning av radiohorisonten", + "losFrequencyDialogDescription": "Med utgångspunkt från k={baselineK} vid {baselineFreq} MHz multiplicerar beräkningen 0.15 × (frequency − {baselineFreq}) / {baselineFreq} för att nå k cirka {kFactor} för det aktuella bandet {frequencyMHz} MHz, 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" } + } + } +} diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 235e4ed..d339ec2 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1718,5 +1718,21 @@ "losPointName": "Назва точки", "losShowPanelTooltip": "Показати панель LOS", "losHidePanelTooltip": "Приховати панель LOS", - "losElevationAttribution": "Дані про висоту: Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "Дані про висоту: Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "Радіогоризонт", + "losLegendLosBeam": "Лінія прямої видимості", + "losLegendTerrain": "Рельєф", + "losFrequencyLabel": "Частота", + "losFrequencyInfoTooltip": "Переглянути деталі розрахунку", + "losFrequencyDialogTitle": "Розрахунок радіогоризонту", + "losFrequencyDialogDescription": "Починаючи з k={baselineK} при {baselineFreq} MHz, розрахунок множить 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, щоб досягти k приблизно {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" } + } + } +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 72f48ad..626cbac 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1718,5 +1718,21 @@ "losPointName": "点名称", "losShowPanelTooltip": "显示 LOS 面板", "losHidePanelTooltip": "隐藏 LOS 面板", - "losElevationAttribution": "高程数据:Open-Meteo (CC BY 4.0)" -} \ No newline at end of file + "losElevationAttribution": "高程数据:Open-Meteo (CC BY 4.0)", + "losLegendRadioHorizon": "无线电地平线", + "losLegendLosBeam": "视距波束", + "losLegendTerrain": "地形", + "losFrequencyLabel": "频率", + "losFrequencyInfoTooltip": "查看计算详情", + "losFrequencyDialogTitle": "无线电地平线计算", + "losFrequencyDialogDescription": "从 {baselineFreq} MHz 的 k={baselineK} 开始,计算将 0.15 × (frequency − {baselineFreq}) / {baselineFreq} 相乘,以在当前频段 {frequencyMHz} MHz 下得到约 k={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" } + } + } +} diff --git a/untranslated.json b/untranslated.json index f9183cb..9e26dfe 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,141 +1 @@ -{ - "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" - ] -} +{} \ No newline at end of file From 78f1a7b28e5e79fdeb5dae7e44fa4f85470d775b Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:12:32 -0500 Subject: [PATCH 20/34] fix: normalize stored frequency --- lib/screens/line_of_sight_map_screen.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 785dfe5..efbdf34 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -993,11 +993,9 @@ class _LineOfSightMapScreenState extends State { ); } - double? _normalizeFrequencyMHz(int? frequencyHz) { - if (frequencyHz == null || frequencyHz <= 0) return null; - if (frequencyHz >= 1000000) return frequencyHz / 1e6; - if (frequencyHz >= 1000) return frequencyHz / 1e3; - return frequencyHz.toDouble(); + double? _normalizeFrequencyMHz(int? frequencyKHz) { + if (frequencyKHz == null || frequencyKHz <= 0) return null; + return frequencyKHz / 1000.0; } } From e2585c099289157145e98c1cfe09d2a62eb47a52 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:44:21 -0500 Subject: [PATCH 21/34] fix: reduce rebuilds in los panel --- lib/screens/line_of_sight_map_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index efbdf34..c8b5a88 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -428,7 +428,7 @@ class _LineOfSightMapScreenState extends State { Widget _buildControlPanel(bool isImperial) { _sanitizeSelection(); final segment = _primarySegmentResult(); - final connector = context.watch(); + final connector = context.read(); final reportedFrequencyMHz = _normalizeFrequencyMHz( connector.currentFreqHz, ); From ea2f35ec2ebd52e3043fa8f04532eb68618e07f9 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:59:18 -0500 Subject: [PATCH 22/34] fix: keep los metadata on failure --- lib/services/line_of_sight_service.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/services/line_of_sight_service.dart b/lib/services/line_of_sight_service.dart index 61e9e27..7f056c8 100644 --- a/lib/services/line_of_sight_service.dart +++ b/lib/services/line_of_sight_service.dart @@ -50,13 +50,13 @@ class LineOfSightResult { const LineOfSightResult.error({ required this.totalDistanceMeters, required this.errorMessage, + this.usedKFactor = 4.0 / 3.0, + this.frequencyMHz, }) : hasData = false, isClear = false, maxObstructionMeters = 0, firstObstructionDistanceMeters = null, - samples = const [], - usedKFactor = 4.0 / 3.0, - frequencyMHz = null; + samples = const []; } class LineOfSightPathSegment { @@ -203,6 +203,8 @@ class LineOfSightService { return LineOfSightResult.error( totalDistanceMeters: totalDistanceMeters, errorMessage: errorElevationUnavailable, + usedKFactor: kFactor, + frequencyMHz: frequencyMHz, ); } @@ -227,9 +229,11 @@ class LineOfSightService { double obstructionToleranceMeters = 0.0, }) { if (points.length < 2 || elevations.length != points.length) { - return const LineOfSightResult.error( + return LineOfSightResult.error( totalDistanceMeters: 0, errorMessage: errorInvalidInput, + usedKFactor: kFactor, + frequencyMHz: frequencyMHz, ); } From 74e29a6c0f6f8f2e257de6f07134bb76468e1185 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:12:04 -0500 Subject: [PATCH 23/34] fix: clamp los profile bounds --- lib/l10n/app_en.arb | 2 +- lib/l10n/app_localizations.dart | 2 +- lib/l10n/app_localizations_en.dart | 2 +- lib/screens/line_of_sight_map_screen.dart | 14 ++++++++------ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 99ce9e2..49f2d34 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1673,7 +1673,7 @@ "losFrequencyLabel": "Frequency", "losFrequencyInfoTooltip": "View calculation details", "losFrequencyDialogTitle": "Radio horizon calculation", - "losFrequencyDialogDescription": "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.", + "losFrequencyDialogDescription": "Starting from k={baselineK} at {baselineFreq} MHz, the calculation adjusts the k-factor for the current {frequencyMHz} MHz band, which defines the curved radio horizon cap.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 1996ad6..5f0cd5e 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -5043,7 +5043,7 @@ abstract class AppLocalizations { /// Explain how the calculation uses the baseline frequency and derived k-factor. /// /// In en, this message translates to: - /// **'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.'** + /// **'Starting from k={baselineK} at {baselineFreq} MHz, the calculation adjusts the k-factor for the current {frequencyMHz} MHz band, which defines the curved radio horizon cap.'** String losFrequencyDialogDescription( double baselineK, double baselineFreq, diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 5c7cf36..98fee85 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2849,7 +2849,7 @@ class AppLocalizationsEn extends AppLocalizations { double frequencyMHz, double 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.'; + return 'Starting from k=$baselineK at $baselineFreq MHz, the calculation adjusts the k-factor for the current $frequencyMHz MHz band, which defines the curved radio horizon cap.'; } @override diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index c8b5a88..be164e3 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -1065,13 +1065,15 @@ class _LosProfilePainter extends CustomPainter { samples.last.terrainMeters, ); - double distanceForCanvasX(double x) => - ((x - horizontalPadding) / chartWidth) * maxDist; + double distanceForCanvasX(double x) { + final normalized = ((x - horizontalPadding) / chartWidth).clamp(0.0, 1.0); + return normalized * maxDist; + } - double elevationToPixel(double elevation) => - size.height - - verticalPadding - - ((elevation - minY) / ySpan) * chartHeight; + double elevationToPixel(double elevation) { + final normalized = ((elevation - minY) / ySpan).clamp(0.0, 1.0); + return size.height - verticalPadding - normalized * chartHeight; + } double extrapolateTerrain(double distance, bool isLeft) { final samplesForSlope = isLeft From 1a9b7b0d55597d8302d44665527678faa39b1a54 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:18:02 -0500 Subject: [PATCH 24/34] chore: remove 0.15 text --- translate_arb.py | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 translate_arb.py diff --git a/translate_arb.py b/translate_arb.py new file mode 100644 index 0000000..737c059 --- /dev/null +++ b/translate_arb.py @@ -0,0 +1,104 @@ +import json +import time +from pathlib import Path + +import requests + + +SOURCE_PATH = Path("lib/l10n/app_en.arb") +L10N_DIR = Path("lib/l10n") +API_URL = "https://libretranslate.de/translate" +DELAY_SECONDS = 0.5 + + +def load_json(path: Path) -> dict: + if not path.exists(): + return {} + return json.loads(path.read_text(encoding="utf-8")) + + +def save_json(path: Path, data: dict) -> None: + path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") + + +def translate_text(text: str, target_locale: str) -> str | None: + payload = { + "q": text, + "source": "en", + "target": target_locale, + "format": "text", + } + try: + response = requests.post(API_URL, json=payload, timeout=30) + response.raise_for_status() + translated = response.json().get("translatedText") + return translated + except requests.RequestException as exc: + print(f"[{target_locale}] Translation failed: {exc}") + except ValueError: + print(f"[{target_locale}] Invalid response from translation service") + return None + + +def translate_locale( + locale: str, + target_path: Path, + english_data: dict, +) -> None: + print(f"Processing locale '{locale}'") + target_data = load_json(target_path) + updated = False + missing_keys = [] + + for key, value in english_data.items(): + if key.startswith("@"): + continue + if not isinstance(value, str): + continue + target_value = target_data.get(key) + if target_value is None or (isinstance(target_value, str) and target_value.strip() == ""): + missing_keys.append((key, value)) + + if not missing_keys: + print(f" -> No missing entries for {locale}") + return + + print(f" -> Translating {len(missing_keys)} entries") + for key, english_text in missing_keys: + time.sleep(DELAY_SECONDS) + translated = translate_text(english_text, locale) + if translated: + target_data[key] = translated + updated = True + else: + print(f" → [{locale}] Keeping English text for {key}") + target_data[key] = english_text + + metadata_key = f"@{key}" + if metadata_key not in target_data: + target_data[metadata_key] = {"description": ""} + updated = True + + if updated: + save_json(target_path, target_data) + print(f" → Saved translations for {locale}") + else: + print(f" → No updates written for {locale}") + + +def main() -> None: + english_data = load_json(SOURCE_PATH) + if not english_data: + print("English source not found or empty") + return + + locales = sorted(L10N_DIR.glob("app_*.arb")) + for path in locales: + if path.name == SOURCE_PATH.name: + continue + locale = path.name.split("_", 1)[1].split(".")[0] + translate_locale(locale, path, english_data) + + +if __name__ == "__main__": + main() From 2188b4972689e058cd35c7ded607f6a45c9dd8b5 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:55:43 -0500 Subject: [PATCH 25/34] fix: refresh los localization --- lib/l10n/app_bg.arb | 20 ++++++++++++++------ lib/l10n/app_de.arb | 20 ++++++++++++++------ lib/l10n/app_en.arb | 18 +++++++++++++----- lib/l10n/app_es.arb | 20 ++++++++++++++------ lib/l10n/app_fr.arb | 20 ++++++++++++++------ lib/l10n/app_it.arb | 20 ++++++++++++++------ lib/l10n/app_localizations_bg.dart | 2 +- lib/l10n/app_localizations_de.dart | 2 +- lib/l10n/app_localizations_es.dart | 2 +- lib/l10n/app_localizations_fr.dart | 2 +- lib/l10n/app_localizations_it.dart | 2 +- lib/l10n/app_localizations_nl.dart | 2 +- lib/l10n/app_localizations_pl.dart | 2 +- lib/l10n/app_localizations_pt.dart | 2 +- lib/l10n/app_localizations_ru.dart | 2 +- lib/l10n/app_localizations_sk.dart | 2 +- lib/l10n/app_localizations_sl.dart | 2 +- lib/l10n/app_localizations_sv.dart | 2 +- lib/l10n/app_localizations_uk.dart | 2 +- lib/l10n/app_localizations_zh.dart | 2 +- lib/l10n/app_nl.arb | 20 ++++++++++++++------ lib/l10n/app_pl.arb | 20 ++++++++++++++------ lib/l10n/app_pt.arb | 20 ++++++++++++++------ lib/l10n/app_ru.arb | 20 ++++++++++++++------ lib/l10n/app_sk.arb | 20 ++++++++++++++------ lib/l10n/app_sl.arb | 20 ++++++++++++++------ lib/l10n/app_sv.arb | 20 ++++++++++++++------ lib/l10n/app_uk.arb | 20 ++++++++++++++------ lib/l10n/app_zh.arb | 20 ++++++++++++++------ 29 files changed, 223 insertions(+), 103 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index c245101..83c35e7 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Честота", "losFrequencyInfoTooltip": "Преглед на детайли за изчислението", "losFrequencyDialogTitle": "Изчисляване на радиохоризонта", - "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {baselineFreq} MHz, изчислението умножава 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, за да достигне k приблизително {kFactor} за текущата лента {frequencyMHz} MHz, което определя извитата граница на радиохоризонта.", + "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {frequencyMHz} MHz, изчислението коригира k-фактора за текущата {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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1f67898..e5243bf 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1753,14 +1753,22 @@ "losFrequencyLabel": "Frequenz", "losFrequencyInfoTooltip": "Details zur Berechnung anzeigen", "losFrequencyDialogTitle": "Berechnung des Funkhorizonts", - "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {baselineFreq} MHz multipliziert die Berechnung 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, um k etwa {kFactor} für das aktuelle Band {frequencyMHz} MHz zu erreichen, was die gekrümmte Funkhorizont-Begrenzung definiert.", + "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {frequencyMHz} MHz passt die Berechnung den k-Faktor für das aktuelle {frequencyMHz} MHz-Band an, das die gekrümmte Funkhorizontobergrenze 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 49f2d34..8f231e7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1677,10 +1677,18 @@ "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } }, "contacts_pathTrace": "Path Trace", @@ -1763,4 +1771,4 @@ "settings_gpxExportShareSubject": "meshcore-open GPX map data export", "snrIndicator_nearByRepeaters": "Nearby Repeaters", "snrIndicator_lastSeen": "Last seen" -} +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 9721f6b..d0bd732 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1753,14 +1753,22 @@ "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 alcanzar k aprox {kFactor} para la banda actual {frequencyMHz} MHz, lo que define el límite curvo del horizonte radioeléctrico.", + "losFrequencyDialogDescription": "A partir de k={baselineK} en {frequencyMHz} MHz, el cálculo ajusta el factor k para la banda actual de {frequencyMHz} MHz, que define el límite curvo del horizonte de 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c6d5de3..81cffc3 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1725,14 +1725,22 @@ "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 env {kFactor} pour la bande actuelle {frequencyMHz} MHz, ce qui définit la limite courbe de l’horizon radio.", + "losFrequencyDialogDescription": "À partir de k={baselineK} à {frequencyMHz} MHz, le calcul ajuste le facteur k pour la bande actuelle de {frequencyMHz} MHz, ce qui définit la limite incurvée 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index a51cb6b..25e3918 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1725,14 +1725,22 @@ "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 circa {kFactor} per la banda corrente {frequencyMHz} MHz, che definisce il limite curvo dell’orizzonte radio.", + "losFrequencyDialogDescription": "Partendo da k={baselineK} a {frequencyMHz} MHz, il calcolo regola il fattore k per l'attuale banda {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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 52c4246..c300e5e 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2892,7 +2892,7 @@ class AppLocalizationsBg extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Започвайки от k=$baselineK при $baselineFreq MHz, изчислението умножава 0.15 × (frequency − $baselineFreq) / $baselineFreq, за да достигне k приблизително $kFactor за текущата лента $frequencyMHz MHz, което определя извитата граница на радиохоризонта.'; + return 'Започвайки от k=$baselineK при $frequencyMHz MHz, изчислението коригира k-фактора за текущата $frequencyMHz MHz лента, която определя границата на извития радиохоризонт.'; } @override diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index e5eb247..a6107e5 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2898,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 etwa $kFactor für das aktuelle Band $frequencyMHz MHz zu erreichen, was die gekrümmte Funkhorizont-Begrenzung definiert.'; + return 'Ausgehend von k=$baselineK bei $frequencyMHz MHz passt die Berechnung den k-Faktor für das aktuelle $frequencyMHz MHz-Band an, das die gekrümmte Funkhorizontobergrenze definiert.'; } @override diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index f411b18..8bd50c7 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2892,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 alcanzar k aprox $kFactor para la banda actual $frequencyMHz MHz, lo que define el límite curvo del horizonte radioeléctrico.'; + return 'A partir de k=$baselineK en $frequencyMHz MHz, el cálculo ajusta el factor k para la banda actual de $frequencyMHz MHz, que define el límite curvo del horizonte de radio.'; } @override diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 2269ea1..d22ede1 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2907,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 env $kFactor pour la bande actuelle $frequencyMHz MHz, ce qui définit la limite courbe de l’horizon radio.'; + return 'À partir de k=$baselineK à $frequencyMHz MHz, le calcul ajuste le facteur k pour la bande actuelle de $frequencyMHz MHz, ce qui définit la limite incurvée de l\'horizon radio.'; } @override diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 91d7c35..0135108 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2892,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 circa $kFactor per la banda corrente $frequencyMHz MHz, che definisce il limite curvo dell’orizzonte radio.'; + return 'Partendo da k=$baselineK a $frequencyMHz MHz, il calcolo regola il fattore k per l\'attuale banda $frequencyMHz MHz, che definisce il limite curvo dell\'orizzonte radio.'; } @override diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 8e03b53..3e9bc0a 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2882,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 ongeveer $kFactor te bereiken voor de huidige band $frequencyMHz MHz, wat de gebogen radiohorizon-grens definieert.'; + return 'Beginnend met k=$baselineK bij $frequencyMHz MHz, wordt bij de berekening de k-factor aangepast voor de huidige $frequencyMHz MHz-band, die de gebogen radiohorizonkap definieert.'; } @override diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 29bbbc4..c0e75fd 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2888,7 +2888,7 @@ class AppLocalizationsPl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Zaczynając od k=$baselineK przy $baselineFreq MHz, obliczenie mnoży 0.15 × (frequency − $baselineFreq) / $baselineFreq, aby osiągnąć k około $kFactor dla bieżącego pasma $frequencyMHz MHz, co definiuje zakrzywioną granicę horyzontu radiowego.'; + return 'Zaczynając od k=$baselineK przy $frequencyMHz MHz, obliczenia korygują współczynnik k dla bieżącego pasma $frequencyMHz MHz, które definiuje zakrzywiony limit horyzontu radiowego.'; } @override diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index e3673f5..de53c86 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2891,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 atingir k aprox $kFactor para a banda atual $frequencyMHz MHz, o que define o limite curvo do horizonte de rádio.'; + return 'Começando em k=$baselineK em $frequencyMHz MHz, o cálculo ajusta o fator k para a banda atual de $frequencyMHz MHz, que define o limite do horizonte de rádio curvo.'; } @override diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 44ccf7c..c32e663 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2894,7 +2894,7 @@ class AppLocalizationsRu extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Начиная с k=$baselineK при $baselineFreq MHz, расчёт умножает 0.15 × (frequency − $baselineFreq) / $baselineFreq, чтобы получить k примерно $kFactor для текущего диапазона $frequencyMHz MHz, что определяет изогнутую границу радиогоризонта.'; + return 'Начиная с k=$baselineK на частоте $frequencyMHz МГц, расчет корректирует коэффициент k для текущего диапазона $frequencyMHz МГц, который определяет изогнутую границу радиогоризонта.'; } @override diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 39c277b..2326e11 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2876,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 približne $kFactor pre aktuálne pásmo $frequencyMHz MHz, čo definuje zakrivenú hranicu rádiového horizontu.'; + return 'Počnúc od k=$baselineK pri $frequencyMHz MHz výpočet upraví k-faktor pre aktuálne pásmo $frequencyMHz MHz, ktorý definuje zakrivený strop rádiového horizontu.'; } @override diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index db973e8..181a894 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2879,7 +2879,7 @@ class AppLocalizationsSl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Začenši z k=$baselineK pri $baselineFreq MHz izračun množi 0.15 × (frequency − $baselineFreq) / $baselineFreq, da doseže k približno $kFactor za trenutni pas $frequencyMHz MHz, kar določa ukrivljeno mejo radijskega horizonta.'; + return 'Začenši od k=$baselineK pri $frequencyMHz MHz, izračun prilagodi k-faktor za trenutni pas $frequencyMHz MHz, ki določa ukrivljeno zgornjo mejo radijskega horizonta.'; } @override diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 8a3f29f..a71a8a5 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2862,7 +2862,7 @@ class AppLocalizationsSv extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Med utgångspunkt från k=$baselineK vid $baselineFreq MHz multiplicerar beräkningen 0.15 × (frequency − $baselineFreq) / $baselineFreq för att nå k cirka $kFactor för det aktuella bandet $frequencyMHz MHz, vilket definierar den krökta radiohorisontgränsen.'; + return 'Med start från k=$baselineK vid $frequencyMHz MHz, justerar beräkningen k-faktorn för det aktuella $frequencyMHz MHz-bandet, som definierar den böjda radiohorisonten.'; } @override diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 1d38ca0..ffdf835 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2902,7 +2902,7 @@ class AppLocalizationsUk extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Починаючи з k=$baselineK при $baselineFreq MHz, розрахунок множить 0.15 × (frequency − $baselineFreq) / $baselineFreq, щоб досягти k приблизно $kFactor для поточного діапазону $frequencyMHz MHz, що визначає вигнуту межу радіогоризонту.'; + return 'Починаючи з k=$baselineK на $frequencyMHz МГц, обчислення коригує k-фактор для поточного діапазону $frequencyMHz МГц, який визначає викривлену межу радіогоризонту.'; } @override diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index fa1a34a..1842466 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2740,7 +2740,7 @@ class AppLocalizationsZh extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return '从 $baselineFreq MHz 的 k=$baselineK 开始,计算将 0.15 × (frequency − $baselineFreq) / $baselineFreq 相乘,以在当前频段 $frequencyMHz MHz 下得到约 k=$kFactor,从而定义弯曲的无线电地平线边界。'; + return '从 $frequencyMHz MHz 处的 k=$baselineK 开始,计算调整当前 $frequencyMHz MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。'; } @override diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index f47a3b9..17e4b3c 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Frequentie", "losFrequencyInfoTooltip": "Bekijk details van de berekening", "losFrequencyDialogTitle": "Berekening van de radiohorizon", - "losFrequencyDialogDescription": "Uitgaande van k={baselineK} bij {baselineFreq} MHz vermenigvuldigt de berekening 0.15 × (frequency − {baselineFreq}) / {baselineFreq} om k ongeveer {kFactor} te bereiken voor de huidige band {frequencyMHz} MHz, wat de gebogen radiohorizon-grens definieert.", + "losFrequencyDialogDescription": "Beginnend met k={baselineK} bij {frequencyMHz} MHz, wordt bij de berekening de k-factor aangepast voor de huidige {frequencyMHz} MHz-band, die de gebogen radiohorizonkap 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 3b56900..db45f75 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Częstotliwość", "losFrequencyInfoTooltip": "Zobacz szczegóły obliczenia", "losFrequencyDialogTitle": "Obliczanie horyzontu radiowego", - "losFrequencyDialogDescription": "Zaczynając od k={baselineK} przy {baselineFreq} MHz, obliczenie mnoży 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, aby osiągnąć k około {kFactor} dla bieżącego pasma {frequencyMHz} MHz, co definiuje zakrzywioną granicę horyzontu radiowego.", + "losFrequencyDialogDescription": "Zaczynając od k={baselineK} przy {frequencyMHz} MHz, obliczenia korygują współczynnik k dla bieżącego pasma {frequencyMHz} MHz, które definiuje zakrzywiony limit 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index a058bff..c3557e5 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1725,14 +1725,22 @@ "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 atingir k aprox {kFactor} para a banda atual {frequencyMHz} MHz, o que define o limite curvo do horizonte de rádio.", + "losFrequencyDialogDescription": "Começando em k={baselineK} em {frequencyMHz} MHz, o cálculo ajusta o fator k para a banda atual de {frequencyMHz} MHz, que define o limite do horizonte de rádio curvo.", "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index f439754..7c8a325 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -965,14 +965,22 @@ "losFrequencyLabel": "Частота", "losFrequencyInfoTooltip": "Просмотреть детали расчёта", "losFrequencyDialogTitle": "Расчёт радиогоризонта", - "losFrequencyDialogDescription": "Начиная с k={baselineK} при {baselineFreq} MHz, расчёт умножает 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, чтобы получить k примерно {kFactor} для текущего диапазона {frequencyMHz} MHz, что определяет изогнутую границу радиогоризонта.", + "losFrequencyDialogDescription": "Начиная с k={baselineK} на частоте {frequencyMHz} МГц, расчет корректирует коэффициент k для текущего диапазона {frequencyMHz} МГц, который определяет изогнутую границу радиогоризонта.", "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 0801b8d..c3d7547 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1725,14 +1725,22 @@ "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 približne {kFactor} pre aktuálne pásmo {frequencyMHz} MHz, čo definuje zakrivenú hranicu rádiového horizontu.", + "losFrequencyDialogDescription": "Počnúc od k={baselineK} pri {frequencyMHz} MHz výpočet upraví k-faktor pre aktuálne pásmo {frequencyMHz} MHz, ktorý definuje zakrivený strop 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index d7e9ab3..1350f79 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Frekvenca", "losFrequencyInfoTooltip": "Prikaži podrobnosti izračuna", "losFrequencyDialogTitle": "Izračun radijskega horizonta", - "losFrequencyDialogDescription": "Začenši z k={baselineK} pri {baselineFreq} MHz izračun množi 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, da doseže k približno {kFactor} za trenutni pas {frequencyMHz} MHz, kar določa ukrivljeno mejo radijskega horizonta.", + "losFrequencyDialogDescription": "Začenši od k={baselineK} pri {frequencyMHz} MHz, izračun prilagodi k-faktor za trenutni pas {frequencyMHz} MHz, ki določa ukrivljeno zgornjo 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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index dcb4069..2394f87 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Frekvens", "losFrequencyInfoTooltip": "Visa detaljer om beräkningen", "losFrequencyDialogTitle": "Beräkning av radiohorisonten", - "losFrequencyDialogDescription": "Med utgångspunkt från k={baselineK} vid {baselineFreq} MHz multiplicerar beräkningen 0.15 × (frequency − {baselineFreq}) / {baselineFreq} för att nå k cirka {kFactor} för det aktuella bandet {frequencyMHz} MHz, vilket definierar den krökta radiohorisontgränsen.", + "losFrequencyDialogDescription": "Med start från k={baselineK} vid {frequencyMHz} MHz, justerar beräkningen k-faktorn för det aktuella {frequencyMHz} MHz-bandet, som definierar den böjda radiohorisonten.", "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index d339ec2..5ead3a2 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "Частота", "losFrequencyInfoTooltip": "Переглянути деталі розрахунку", "losFrequencyDialogTitle": "Розрахунок радіогоризонту", - "losFrequencyDialogDescription": "Починаючи з k={baselineK} при {baselineFreq} MHz, розрахунок множить 0.15 × (frequency − {baselineFreq}) / {baselineFreq}, щоб досягти k приблизно {kFactor} для поточного діапазону {frequencyMHz} MHz, що визначає вигнуту межу радіогоризонту.", + "losFrequencyDialogDescription": "Починаючи з k={baselineK} на {frequencyMHz} МГц, обчислення коригує k-фактор для поточного діапазону {frequencyMHz} МГц, який визначає викривлену межу радіогоризонту.", "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 626cbac..5ecdebf 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1725,14 +1725,22 @@ "losFrequencyLabel": "频率", "losFrequencyInfoTooltip": "查看计算详情", "losFrequencyDialogTitle": "无线电地平线计算", - "losFrequencyDialogDescription": "从 {baselineFreq} MHz 的 k={baselineK} 开始,计算将 0.15 × (frequency − {baselineFreq}) / {baselineFreq} 相乘,以在当前频段 {frequencyMHz} MHz 下得到约 k={kFactor},从而定义弯曲的无线电地平线边界。", + "losFrequencyDialogDescription": "从 {frequencyMHz} MHz 处的 k={baselineK} 开始,计算调整当前 {frequencyMHz} MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。", "@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" } + "baselineK": { + "type": "double" + }, + "baselineFreq": { + "type": "double" + }, + "frequencyMHz": { + "type": "double" + }, + "kFactor": { + "type": "double" + } } } -} +} \ No newline at end of file From ddc87f3a274234d22c2c54c7c3717490a45929ec Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:14:00 -0500 Subject: [PATCH 26/34] chore: remove translation script --- translate_arb.py | 104 ----------------------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 translate_arb.py diff --git a/translate_arb.py b/translate_arb.py deleted file mode 100644 index 737c059..0000000 --- a/translate_arb.py +++ /dev/null @@ -1,104 +0,0 @@ -import json -import time -from pathlib import Path - -import requests - - -SOURCE_PATH = Path("lib/l10n/app_en.arb") -L10N_DIR = Path("lib/l10n") -API_URL = "https://libretranslate.de/translate" -DELAY_SECONDS = 0.5 - - -def load_json(path: Path) -> dict: - if not path.exists(): - return {} - return json.loads(path.read_text(encoding="utf-8")) - - -def save_json(path: Path, data: dict) -> None: - path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") - - -def translate_text(text: str, target_locale: str) -> str | None: - payload = { - "q": text, - "source": "en", - "target": target_locale, - "format": "text", - } - try: - response = requests.post(API_URL, json=payload, timeout=30) - response.raise_for_status() - translated = response.json().get("translatedText") - return translated - except requests.RequestException as exc: - print(f"[{target_locale}] Translation failed: {exc}") - except ValueError: - print(f"[{target_locale}] Invalid response from translation service") - return None - - -def translate_locale( - locale: str, - target_path: Path, - english_data: dict, -) -> None: - print(f"Processing locale '{locale}'") - target_data = load_json(target_path) - updated = False - missing_keys = [] - - for key, value in english_data.items(): - if key.startswith("@"): - continue - if not isinstance(value, str): - continue - target_value = target_data.get(key) - if target_value is None or (isinstance(target_value, str) and target_value.strip() == ""): - missing_keys.append((key, value)) - - if not missing_keys: - print(f" -> No missing entries for {locale}") - return - - print(f" -> Translating {len(missing_keys)} entries") - for key, english_text in missing_keys: - time.sleep(DELAY_SECONDS) - translated = translate_text(english_text, locale) - if translated: - target_data[key] = translated - updated = True - else: - print(f" → [{locale}] Keeping English text for {key}") - target_data[key] = english_text - - metadata_key = f"@{key}" - if metadata_key not in target_data: - target_data[metadata_key] = {"description": ""} - updated = True - - if updated: - save_json(target_path, target_data) - print(f" → Saved translations for {locale}") - else: - print(f" → No updates written for {locale}") - - -def main() -> None: - english_data = load_json(SOURCE_PATH) - if not english_data: - print("English source not found or empty") - return - - locales = sorted(L10N_DIR.glob("app_*.arb")) - for path in locales: - if path.name == SOURCE_PATH.name: - continue - locale = path.name.split("_", 1)[1].split(".")[0] - translate_locale(locale, path, english_data) - - -if __name__ == "__main__": - main() From faefef14ff2a0f22c3a6db24cbd9783bd6939613 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:29:36 -0500 Subject: [PATCH 27/34] fix: restore baseline freq in los text --- lib/l10n/app_bg.arb | 4 ++-- lib/l10n/app_de.arb | 4 ++-- lib/l10n/app_es.arb | 4 ++-- lib/l10n/app_fr.arb | 4 ++-- lib/l10n/app_it.arb | 4 ++-- lib/l10n/app_localizations_bg.dart | 2 +- lib/l10n/app_localizations_de.dart | 2 +- lib/l10n/app_localizations_es.dart | 2 +- lib/l10n/app_localizations_fr.dart | 2 +- lib/l10n/app_localizations_it.dart | 2 +- lib/l10n/app_localizations_nl.dart | 2 +- lib/l10n/app_localizations_pl.dart | 2 +- lib/l10n/app_localizations_pt.dart | 2 +- lib/l10n/app_localizations_ru.dart | 2 +- lib/l10n/app_localizations_sk.dart | 2 +- lib/l10n/app_localizations_sl.dart | 2 +- lib/l10n/app_localizations_sv.dart | 2 +- lib/l10n/app_localizations_uk.dart | 2 +- lib/l10n/app_localizations_zh.dart | 2 +- lib/l10n/app_nl.arb | 4 ++-- lib/l10n/app_pl.arb | 4 ++-- lib/l10n/app_pt.arb | 4 ++-- lib/l10n/app_ru.arb | 4 ++-- lib/l10n/app_sk.arb | 4 ++-- lib/l10n/app_sl.arb | 4 ++-- lib/l10n/app_sv.arb | 4 ++-- lib/l10n/app_uk.arb | 4 ++-- lib/l10n/app_zh.arb | 4 ++-- 28 files changed, 42 insertions(+), 42 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 83c35e7..b94b2cb 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Честота", "losFrequencyInfoTooltip": "Преглед на детайли за изчислението", "losFrequencyDialogTitle": "Изчисляване на радиохоризонта", - "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {frequencyMHz} MHz, изчислението коригира k-фактора за текущата {frequencyMHz} MHz лента, която определя границата на извития радиохоризонт.", + "losFrequencyDialogDescription": "Започвайки от k={baselineK} при {baselineFreq} MHz, изчислението коригира k-фактора за текущата {frequencyMHz} MHz лента, която определя границата на извития радиохоризонт.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e5243bf..3963e31 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1753,7 +1753,7 @@ "losFrequencyLabel": "Frequenz", "losFrequencyInfoTooltip": "Details zur Berechnung anzeigen", "losFrequencyDialogTitle": "Berechnung des Funkhorizonts", - "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {frequencyMHz} MHz passt die Berechnung den k-Faktor für das aktuelle {frequencyMHz} MHz-Band an, das die gekrümmte Funkhorizontobergrenze definiert.", + "losFrequencyDialogDescription": "Ausgehend von k={baselineK} bei {baselineFreq} MHz passt die Berechnung den k-Faktor für das aktuelle {frequencyMHz} MHz-Band an, das die gekrümmte Funkhorizontobergrenze definiert.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1771,4 +1771,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index d0bd732..d194093 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1753,7 +1753,7 @@ "losFrequencyLabel": "Frecuencia", "losFrequencyInfoTooltip": "Ver detalles del cálculo", "losFrequencyDialogTitle": "Cálculo del horizonte radioeléctrico", - "losFrequencyDialogDescription": "A partir de k={baselineK} en {frequencyMHz} MHz, el cálculo ajusta el factor k para la banda actual de {frequencyMHz} MHz, que define el límite curvo del horizonte de radio.", + "losFrequencyDialogDescription": "A partir de k={baselineK} en {baselineFreq} MHz, el cálculo ajusta el factor k para la banda actual de {frequencyMHz} MHz, que define el límite curvo del horizonte de radio.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1771,4 +1771,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 81cffc3..f3e9ea8 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Fréquence", "losFrequencyInfoTooltip": "Voir les détails du calcul", "losFrequencyDialogTitle": "Calcul de l’horizon radio", - "losFrequencyDialogDescription": "À partir de k={baselineK} à {frequencyMHz} MHz, le calcul ajuste le facteur k pour la bande actuelle de {frequencyMHz} MHz, ce qui définit la limite incurvée de l'horizon radio.", + "losFrequencyDialogDescription": "À partir de k={baselineK} à {baselineFreq} MHz, le calcul ajuste le facteur k pour la bande actuelle de {frequencyMHz} MHz, ce qui définit la limite incurvée de l'horizon radio.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 25e3918..8b095f5 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frequenza", "losFrequencyInfoTooltip": "Visualizza i dettagli del calcolo", "losFrequencyDialogTitle": "Calcolo dell’orizzonte radio", - "losFrequencyDialogDescription": "Partendo da k={baselineK} a {frequencyMHz} MHz, il calcolo regola il fattore k per l'attuale banda {frequencyMHz} MHz, che definisce il limite curvo dell'orizzonte radio.", + "losFrequencyDialogDescription": "Partendo da k={baselineK} a {baselineFreq} MHz, il calcolo regola il fattore k per l'attuale banda {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": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index c300e5e..91e5a94 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2892,7 +2892,7 @@ class AppLocalizationsBg extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Започвайки от k=$baselineK при $frequencyMHz MHz, изчислението коригира k-фактора за текущата $frequencyMHz MHz лента, която определя границата на извития радиохоризонт.'; + return 'Започвайки от k=$baselineK при $baselineFreq MHz, изчислението коригира k-фактора за текущата $frequencyMHz MHz лента, която определя границата на извития радиохоризонт.'; } @override diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index a6107e5..4c591e5 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2898,7 +2898,7 @@ class AppLocalizationsDe extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Ausgehend von k=$baselineK bei $frequencyMHz MHz passt die Berechnung den k-Faktor für das aktuelle $frequencyMHz MHz-Band an, das die gekrümmte Funkhorizontobergrenze definiert.'; + return 'Ausgehend von k=$baselineK bei $baselineFreq MHz passt die Berechnung den k-Faktor für das aktuelle $frequencyMHz MHz-Band an, das die gekrümmte Funkhorizontobergrenze definiert.'; } @override diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 8bd50c7..b868aad 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2892,7 +2892,7 @@ class AppLocalizationsEs extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'A partir de k=$baselineK en $frequencyMHz MHz, el cálculo ajusta el factor k para la banda actual de $frequencyMHz MHz, que define el límite curvo del horizonte de radio.'; + return 'A partir de k=$baselineK en $baselineFreq MHz, el cálculo ajusta el factor k para la banda actual de $frequencyMHz MHz, que define el límite curvo del horizonte de radio.'; } @override diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index d22ede1..a939e09 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2907,7 +2907,7 @@ class AppLocalizationsFr extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'À partir de k=$baselineK à $frequencyMHz MHz, le calcul ajuste le facteur k pour la bande actuelle de $frequencyMHz MHz, ce qui définit la limite incurvée de l\'horizon radio.'; + return 'À partir de k=$baselineK à $baselineFreq MHz, le calcul ajuste le facteur k pour la bande actuelle de $frequencyMHz MHz, ce qui définit la limite incurvée de l\'horizon radio.'; } @override diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 0135108..d4cda69 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2892,7 +2892,7 @@ class AppLocalizationsIt extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Partendo da k=$baselineK a $frequencyMHz MHz, il calcolo regola il fattore k per l\'attuale banda $frequencyMHz MHz, che definisce il limite curvo dell\'orizzonte radio.'; + return 'Partendo da k=$baselineK a $baselineFreq MHz, il calcolo regola il fattore k per l\'attuale banda $frequencyMHz MHz, che definisce il limite curvo dell\'orizzonte radio.'; } @override diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 3e9bc0a..5c38227 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2882,7 +2882,7 @@ class AppLocalizationsNl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Beginnend met k=$baselineK bij $frequencyMHz MHz, wordt bij de berekening de k-factor aangepast voor de huidige $frequencyMHz MHz-band, die de gebogen radiohorizonkap definieert.'; + return 'Beginnend met k=$baselineK bij $baselineFreq MHz, wordt bij de berekening de k-factor aangepast voor de huidige $frequencyMHz MHz-band, die de gebogen radiohorizonkap definieert.'; } @override diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index c0e75fd..6f68786 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2888,7 +2888,7 @@ class AppLocalizationsPl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Zaczynając od k=$baselineK przy $frequencyMHz MHz, obliczenia korygują współczynnik k dla bieżącego pasma $frequencyMHz MHz, które definiuje zakrzywiony limit horyzontu radiowego.'; + return 'Zaczynając od k=$baselineK przy $baselineFreq MHz, obliczenia korygują współczynnik k dla bieżącego pasma $frequencyMHz MHz, które definiuje zakrzywiony limit horyzontu radiowego.'; } @override diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index de53c86..cedf400 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2891,7 +2891,7 @@ class AppLocalizationsPt extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Começando em k=$baselineK em $frequencyMHz MHz, o cálculo ajusta o fator k para a banda atual de $frequencyMHz MHz, que define o limite do horizonte de rádio curvo.'; + return 'Começando em k=$baselineK em $baselineFreq MHz, o cálculo ajusta o fator k para a banda atual de $frequencyMHz MHz, que define o limite do horizonte de rádio curvo.'; } @override diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index c32e663..d35b174 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2894,7 +2894,7 @@ class AppLocalizationsRu extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Начиная с k=$baselineK на частоте $frequencyMHz МГц, расчет корректирует коэффициент k для текущего диапазона $frequencyMHz МГц, который определяет изогнутую границу радиогоризонта.'; + return 'Начиная с k=$baselineK на частоте $baselineFreq МГц, расчет корректирует коэффициент k для текущего диапазона $frequencyMHz МГц, который определяет изогнутую границу радиогоризонта.'; } @override diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 2326e11..c4f9a92 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2876,7 +2876,7 @@ class AppLocalizationsSk extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Počnúc od k=$baselineK pri $frequencyMHz MHz výpočet upraví k-faktor pre aktuálne pásmo $frequencyMHz MHz, ktorý definuje zakrivený strop rádiového horizontu.'; + return 'Počnúc od k=$baselineK pri $baselineFreq MHz výpočet upraví k-faktor pre aktuálne pásmo $frequencyMHz MHz, ktorý definuje zakrivený strop rádiového horizontu.'; } @override diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 181a894..a012ef1 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2879,7 +2879,7 @@ class AppLocalizationsSl extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Začenši od k=$baselineK pri $frequencyMHz MHz, izračun prilagodi k-faktor za trenutni pas $frequencyMHz MHz, ki določa ukrivljeno zgornjo mejo radijskega horizonta.'; + return 'Začenši od k=$baselineK pri $baselineFreq MHz, izračun prilagodi k-faktor za trenutni pas $frequencyMHz MHz, ki določa ukrivljeno zgornjo mejo radijskega horizonta.'; } @override diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index a71a8a5..abfd89c 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2862,7 +2862,7 @@ class AppLocalizationsSv extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Med start från k=$baselineK vid $frequencyMHz MHz, justerar beräkningen k-faktorn för det aktuella $frequencyMHz MHz-bandet, som definierar den böjda radiohorisonten.'; + return 'Med start från k=$baselineK vid $baselineFreq MHz, justerar beräkningen k-faktorn för det aktuella $frequencyMHz MHz-bandet, som definierar den böjda radiohorisonten.'; } @override diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index ffdf835..c6b8ff2 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2902,7 +2902,7 @@ class AppLocalizationsUk extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return 'Починаючи з k=$baselineK на $frequencyMHz МГц, обчислення коригує k-фактор для поточного діапазону $frequencyMHz МГц, який визначає викривлену межу радіогоризонту.'; + return 'Починаючи з k=$baselineK на $baselineFreq МГц, обчислення коригує k-фактор для поточного діапазону $frequencyMHz МГц, який визначає викривлену межу радіогоризонту.'; } @override diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 1842466..5677c09 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2740,7 +2740,7 @@ class AppLocalizationsZh extends AppLocalizations { double frequencyMHz, double kFactor, ) { - return '从 $frequencyMHz MHz 处的 k=$baselineK 开始,计算调整当前 $frequencyMHz MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。'; + return '从 $baselineFreq MHz 处的 k=$baselineK 开始,计算调整当前 $frequencyMHz MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。'; } @override diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 17e4b3c..a94560b 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frequentie", "losFrequencyInfoTooltip": "Bekijk details van de berekening", "losFrequencyDialogTitle": "Berekening van de radiohorizon", - "losFrequencyDialogDescription": "Beginnend met k={baselineK} bij {frequencyMHz} MHz, wordt bij de berekening de k-factor aangepast voor de huidige {frequencyMHz} MHz-band, die de gebogen radiohorizonkap definieert.", + "losFrequencyDialogDescription": "Beginnend met k={baselineK} bij {baselineFreq} MHz, wordt bij de berekening de k-factor aangepast voor de huidige {frequencyMHz} MHz-band, die de gebogen radiohorizonkap definieert.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index db45f75..2af1058 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Częstotliwość", "losFrequencyInfoTooltip": "Zobacz szczegóły obliczenia", "losFrequencyDialogTitle": "Obliczanie horyzontu radiowego", - "losFrequencyDialogDescription": "Zaczynając od k={baselineK} przy {frequencyMHz} MHz, obliczenia korygują współczynnik k dla bieżącego pasma {frequencyMHz} MHz, które definiuje zakrzywiony limit horyzontu radiowego.", + "losFrequencyDialogDescription": "Zaczynając od k={baselineK} przy {baselineFreq} MHz, obliczenia korygują współczynnik k dla bieżącego pasma {frequencyMHz} MHz, które definiuje zakrzywiony limit horyzontu radiowego.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index c3557e5..c9d3724 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frequência", "losFrequencyInfoTooltip": "Ver detalhes do cálculo", "losFrequencyDialogTitle": "Cálculo do horizonte de rádio", - "losFrequencyDialogDescription": "Começando em k={baselineK} em {frequencyMHz} MHz, o cálculo ajusta o fator k para a banda atual de {frequencyMHz} MHz, que define o limite do horizonte de rádio curvo.", + "losFrequencyDialogDescription": "Começando em k={baselineK} em {baselineFreq} MHz, o cálculo ajusta o fator k para a banda atual de {frequencyMHz} MHz, que define o limite do horizonte de rádio curvo.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 7c8a325..e1a2066 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -965,7 +965,7 @@ "losFrequencyLabel": "Частота", "losFrequencyInfoTooltip": "Просмотреть детали расчёта", "losFrequencyDialogTitle": "Расчёт радиогоризонта", - "losFrequencyDialogDescription": "Начиная с k={baselineK} на частоте {frequencyMHz} МГц, расчет корректирует коэффициент k для текущего диапазона {frequencyMHz} МГц, который определяет изогнутую границу радиогоризонта.", + "losFrequencyDialogDescription": "Начиная с k={baselineK} на частоте {baselineFreq} МГц, расчет корректирует коэффициент k для текущего диапазона {frequencyMHz} МГц, который определяет изогнутую границу радиогоризонта.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -983,4 +983,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index c3d7547..34e5933 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frekvencia", "losFrequencyInfoTooltip": "Zobraziť podrobnosti výpočtu", "losFrequencyDialogTitle": "Výpočet rádiového horizontu", - "losFrequencyDialogDescription": "Počnúc od k={baselineK} pri {frequencyMHz} MHz výpočet upraví k-faktor pre aktuálne pásmo {frequencyMHz} MHz, ktorý definuje zakrivený strop rádiového horizontu.", + "losFrequencyDialogDescription": "Počnúc od k={baselineK} pri {baselineFreq} MHz výpočet upraví k-faktor pre aktuálne pásmo {frequencyMHz} MHz, ktorý definuje zakrivený strop rádiového horizontu.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 1350f79..1371f97 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frekvenca", "losFrequencyInfoTooltip": "Prikaži podrobnosti izračuna", "losFrequencyDialogTitle": "Izračun radijskega horizonta", - "losFrequencyDialogDescription": "Začenši od k={baselineK} pri {frequencyMHz} MHz, izračun prilagodi k-faktor za trenutni pas {frequencyMHz} MHz, ki določa ukrivljeno zgornjo mejo radijskega horizonta.", + "losFrequencyDialogDescription": "Začenši od k={baselineK} pri {baselineFreq} MHz, izračun prilagodi k-faktor za trenutni pas {frequencyMHz} MHz, ki določa ukrivljeno zgornjo mejo radijskega horizonta.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 2394f87..2bdaec4 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Frekvens", "losFrequencyInfoTooltip": "Visa detaljer om beräkningen", "losFrequencyDialogTitle": "Beräkning av radiohorisonten", - "losFrequencyDialogDescription": "Med start från k={baselineK} vid {frequencyMHz} MHz, justerar beräkningen k-faktorn för det aktuella {frequencyMHz} MHz-bandet, som definierar den böjda radiohorisonten.", + "losFrequencyDialogDescription": "Med start från k={baselineK} vid {baselineFreq} MHz, justerar beräkningen k-faktorn för det aktuella {frequencyMHz} MHz-bandet, som definierar den böjda radiohorisonten.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 5ead3a2..13d9362 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "Частота", "losFrequencyInfoTooltip": "Переглянути деталі розрахунку", "losFrequencyDialogTitle": "Розрахунок радіогоризонту", - "losFrequencyDialogDescription": "Починаючи з k={baselineK} на {frequencyMHz} МГц, обчислення коригує k-фактор для поточного діапазону {frequencyMHz} МГц, який визначає викривлену межу радіогоризонту.", + "losFrequencyDialogDescription": "Починаючи з k={baselineK} на {baselineFreq} МГц, обчислення коригує k-фактор для поточного діапазону {frequencyMHz} МГц, який визначає викривлену межу радіогоризонту.", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 5ecdebf..b2dc330 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1725,7 +1725,7 @@ "losFrequencyLabel": "频率", "losFrequencyInfoTooltip": "查看计算详情", "losFrequencyDialogTitle": "无线电地平线计算", - "losFrequencyDialogDescription": "从 {frequencyMHz} MHz 处的 k={baselineK} 开始,计算调整当前 {frequencyMHz} MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。", + "losFrequencyDialogDescription": "从 {baselineFreq} MHz 处的 k={baselineK} 开始,计算调整当前 {frequencyMHz} MHz 频段的 k 因子,该因子定义了弯曲的无线电范围上限。", "@losFrequencyDialogDescription": { "description": "Explain how the calculation uses the baseline frequency and derived k-factor.", "placeholders": { @@ -1743,4 +1743,4 @@ } } } -} \ No newline at end of file +} From 6065059241c3c884e559c45c4393db42a6615880 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:35:51 -0500 Subject: [PATCH 28/34] fix: keep los panel reactive --- lib/screens/line_of_sight_map_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index be164e3..196cd2e 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -111,7 +111,7 @@ class _LineOfSightMapScreenState extends State { }); try { - final connector = context.read(); + final connector = context.watch(); final frequencyMHz = _normalizeFrequencyMHz(connector.currentFreqHz); final result = await _lineOfSightService.analyzePath( [start.point, end.point], From 0f17e2382cb2dea3176eae9372b23dfff5205d60 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 22:41:32 -0500 Subject: [PATCH 29/34] feat(chat): add global pinch-to-zoom text scaling via ChatTextScaleService --- lib/main.dart | 8 ++ lib/screens/channel_chat_screen.dart | 118 +++++++++++++-------- lib/screens/chat_screen.dart | 123 +++++++++++++--------- lib/services/chat_text_scale_service.dart | 45 ++++++++ lib/widgets/chat_zoom_wrapper.dart | 45 ++++++++ 5 files changed, 247 insertions(+), 92 deletions(-) create mode 100644 lib/services/chat_text_scale_service.dart create mode 100644 lib/widgets/chat_zoom_wrapper.dart diff --git a/lib/main.dart b/lib/main.dart index 3650a7e..5a11188 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'services/ble_debug_log_service.dart'; import 'services/app_debug_log_service.dart'; import 'services/background_service.dart'; import 'services/map_tile_cache_service.dart'; +import 'services/chat_text_scale_service.dart'; import 'storage/prefs_manager.dart'; import 'utils/app_logger.dart'; @@ -34,6 +35,7 @@ void main() async { final appDebugLogService = AppDebugLogService(); final backgroundService = BackgroundService(); final mapTileCacheService = MapTileCacheService(); + final chatTextScaleService = ChatTextScaleService(); // Load settings await appSettingsService.loadSettings(); @@ -50,6 +52,8 @@ void main() async { await backgroundService.initialize(); _registerThirdPartyLicenses(); + await chatTextScaleService.initialize(); + // Wire up connector with services connector.initialize( retryService: retryService, @@ -78,6 +82,7 @@ void main() async { bleDebugLogService: bleDebugLogService, appDebugLogService: appDebugLogService, mapTileCacheService: mapTileCacheService, + chatTextScaleService: chatTextScaleService, ), ); } @@ -112,6 +117,7 @@ class MeshCoreApp extends StatelessWidget { final BleDebugLogService bleDebugLogService; final AppDebugLogService appDebugLogService; final MapTileCacheService mapTileCacheService; + final ChatTextScaleService chatTextScaleService; const MeshCoreApp({ super.key, @@ -123,6 +129,7 @@ class MeshCoreApp extends StatelessWidget { required this.bleDebugLogService, required this.appDebugLogService, required this.mapTileCacheService, + required this.chatTextScaleService, }); @override @@ -135,6 +142,7 @@ class MeshCoreApp extends StatelessWidget { ChangeNotifierProvider.value(value: appSettingsService), ChangeNotifierProvider.value(value: bleDebugLogService), ChangeNotifierProvider.value(value: appDebugLogService), + ChangeNotifierProvider.value(value: chatTextScaleService), Provider.value(value: storage), Provider.value(value: mapTileCacheService), ], diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index 9df91c3..79d30e5 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -18,7 +18,9 @@ import '../l10n/l10n.dart'; import '../models/channel.dart'; import '../models/channel_message.dart'; import '../services/app_settings_service.dart'; +import '../services/chat_text_scale_service.dart'; import '../utils/emoji_utils.dart'; +import '../widgets/chat_zoom_wrapper.dart'; import '../widgets/emoji_picker.dart'; import '../widgets/gif_message.dart'; import '../widgets/jump_to_bottom_button.dart'; @@ -219,37 +221,50 @@ class _ChannelChatScreenState extends State { return Stack( children: [ - ListView.builder( - reverse: true, // List grows from bottom up - controller: _scrollController, - padding: const EdgeInsets.all(8), - itemCount: itemCount, - itemBuilder: (context, index) { - // Loading indicator now appears at end (bottom) of reversed list - if (_isLoadingOlder && index == itemCount - 1) { - return const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Center( - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, + ChatZoomWrapper( + child: ListView.builder( + reverse: true, // List grows from bottom up + controller: _scrollController, + padding: const EdgeInsets.all(8), + itemCount: itemCount, + itemBuilder: (context, index) { + // Loading indicator now appears at end (bottom) of reversed list + if (_isLoadingOlder && index == itemCount - 1) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + ), ), ), + ); + } + final messageIndex = index; + final message = reversedMessages[messageIndex]; + if (!_messageKeys.containsKey(message.messageId)) { + _messageKeys[message.messageId] = GlobalKey(); + } + return Container( + key: _messageKeys[message.messageId]!, + child: Builder( + builder: (context) { + final textScale = context + .select( + (service) => service.scale, + ); + return _buildMessageBubble( + message, + textScale, + ); + }, ), ); - } - final messageIndex = index; - final message = reversedMessages[messageIndex]; - if (!_messageKeys.containsKey(message.messageId)) { - _messageKeys[message.messageId] = GlobalKey(); - } - return Container( - key: _messageKeys[message.messageId]!, - child: _buildMessageBubble(message), - ); - }, + }, + ), ), JumpToBottomButton(scrollController: _scrollController), ], @@ -264,7 +279,7 @@ class _ChannelChatScreenState extends State { ); } - Widget _buildMessageBubble(ChannelMessage message) { + Widget _buildMessageBubble(ChannelMessage message, double textScale) { final settingsService = context.watch(); final enableTracing = settingsService.settings.enableMessageTracing; final isOutgoing = message.isOutgoing; @@ -278,6 +293,7 @@ class _ChannelChatScreenState extends State { const maxSwipeOffset = 64.0; const replySwipeThreshold = 64.0; + const bodyFontSize = 14.0; final messageBody = Column( crossAxisAlignment: isOutgoing ? CrossAxisAlignment.end @@ -334,7 +350,7 @@ class _ChannelChatScreenState extends State { if (gifId == null) const SizedBox(height: 4), ], if (message.replyToMessageId != null) ...[ - _buildReplyPreview(message), + _buildReplyPreview(message, textScale), const SizedBox(height: 8), ], if (poi != null) @@ -342,6 +358,7 @@ class _ChannelChatScreenState extends State { context, poi, isOutgoing, + textScale, trailing: (!enableTracing && isOutgoing) ? Padding( padding: const EdgeInsets.only(bottom: 2), @@ -415,9 +432,11 @@ class _ChannelChatScreenState extends State { Flexible( child: Linkify( text: message.text, - style: const TextStyle(fontSize: 14), - linkStyle: const TextStyle( - fontSize: 14, + style: TextStyle( + fontSize: bodyFontSize * textScale, + ), + linkStyle: TextStyle( + fontSize: bodyFontSize * textScale, color: Colors.green, decoration: TextDecoration.underline, ), @@ -595,7 +614,7 @@ class _ChannelChatScreenState extends State { ); } - Widget _buildReplyPreview(ChannelMessage message) { + Widget _buildReplyPreview(ChannelMessage message, double textScale) { final connector = context.read(); final isOwnNode = message.replyToSenderName == connector.selfName; final replyText = message.replyToText ?? ''; @@ -623,7 +642,7 @@ class _ChannelChatScreenState extends State { const SizedBox(width: 4), Text( context.l10n.chat_location, - style: TextStyle(fontSize: 12, color: previewTextColor), + style: TextStyle(fontSize: 12 * textScale, color: previewTextColor), ), ], ); @@ -633,7 +652,7 @@ class _ChannelChatScreenState extends State { maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: 12, + fontSize: 12 * textScale, color: previewTextColor, fontStyle: FontStyle.italic, ), @@ -657,7 +676,7 @@ class _ChannelChatScreenState extends State { Text( context.l10n.chat_replyTo(message.replyToSenderName ?? ''), style: TextStyle( - fontSize: 11, + fontSize: 11 * textScale, fontWeight: FontWeight.bold, color: isOwnNode ? Theme.of(context).colorScheme.primary @@ -736,7 +755,8 @@ class _ChannelChatScreenState extends State { Widget _buildPoiMessage( BuildContext context, _PoiInfo poi, - bool isOutgoing, { + bool isOutgoing, + double textScale, { Widget? trailing, }) { final colorScheme = Theme.of(context).colorScheme; @@ -774,12 +794,16 @@ class _ChannelChatScreenState extends State { children: [ Text( context.l10n.chat_poiShared, - style: TextStyle(color: textColor, fontWeight: FontWeight.w600), + style: TextStyle( + color: textColor, + fontWeight: FontWeight.w600, + fontSize: 14 * textScale, + ), ), if (poi.label.isNotEmpty) Text( poi.label, - style: TextStyle(color: metaColor, fontSize: 12), + style: TextStyle(color: metaColor, fontSize: 12 * textScale), ), ], ), @@ -849,7 +873,7 @@ class _ChannelChatScreenState extends State { return colors[hash.abs() % colors.length]; } - Widget _buildReplyBanner() { + Widget _buildReplyBanner(double textScale) { final message = _replyingToMessage!; return Container( width: double.infinity, @@ -875,7 +899,7 @@ class _ChannelChatScreenState extends State { Text( context.l10n.chat_replyingTo(message.senderName), style: TextStyle( - fontSize: 12, + fontSize: 12 * textScale, fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onSecondaryContainer, ), @@ -885,7 +909,7 @@ class _ChannelChatScreenState extends State { maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: 11, + fontSize: 11 * textScale, color: Theme.of( context, ).colorScheme.onSecondaryContainer.withValues(alpha: 0.7), @@ -912,7 +936,15 @@ class _ChannelChatScreenState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - if (_replyingToMessage != null) _buildReplyBanner(), + if (_replyingToMessage != null) + Builder( + builder: (context) { + final textScale = context.select( + (service) => service.scale, + ); + return _buildReplyBanner(textScale); + }, + ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index 3556d6d..d623f33 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -22,7 +22,9 @@ import '../models/contact.dart'; import '../models/message.dart'; import '../models/path_history.dart'; import '../services/app_settings_service.dart'; +import '../services/chat_text_scale_service.dart'; import '../services/path_history_service.dart'; +import '../widgets/chat_zoom_wrapper.dart'; import '../widgets/elements_ui.dart'; import 'channel_message_path_screen.dart'; import 'map_screen.dart'; @@ -270,52 +272,62 @@ class _ChatScreenState extends State { _scrollController.scrollToBottomIfAtBottom(); }); - return ListView.builder( - reverse: true, // List grows from bottom up - controller: _scrollController, - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), - itemCount: itemCount, - itemBuilder: (context, index) { - // Loading indicator now appears at end (bottom) of reversed list - if (_isLoadingOlder && index == itemCount - 1) { - return const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Center( - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), + return ChatZoomWrapper( + child: ListView.builder( + reverse: true, // List grows from bottom up + controller: _scrollController, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), + itemCount: itemCount, + itemBuilder: (context, index) { + // Loading indicator now appears at end (bottom) of reversed list + if (_isLoadingOlder && index == itemCount - 1) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ), ), - ), - ); - } - final messageIndex = index; - Contact contact = widget.contact; - final message = reversedMessages[messageIndex]; - String fourByteHex = ''; - if (widget.contact.type == advTypeRoom) { - contact = _resolveContactFrom4Bytes( - connector, - message.fourByteRoomContactKey.isEmpty - ? Uint8List.fromList([0, 0, 0, 0]) - : message.fourByteRoomContactKey, - ); - fourByteHex = message.fourByteRoomContactKey - .map((b) => b.toRadixString(16).padLeft(2, '0')) - .join() - .toUpperCase(); - } + ); + } + final messageIndex = index; + Contact contact = widget.contact; + final message = reversedMessages[messageIndex]; + String fourByteHex = ''; + if (widget.contact.type == advTypeRoom) { + contact = _resolveContactFrom4Bytes( + connector, + message.fourByteRoomContactKey.isEmpty + ? Uint8List.fromList([0, 0, 0, 0]) + : message.fourByteRoomContactKey, + ); + fourByteHex = message.fourByteRoomContactKey + .map((b) => b.toRadixString(16).padLeft(2, '0')) + .join() + .toUpperCase(); + } - return _MessageBubble( - message: message, - senderName: widget.contact.type == advTypeRoom - ? "${contact.name} [$fourByteHex]" - : contact.name, - isRoomServer: widget.contact.type == advTypeRoom, - onTap: () => _openMessagePath(message, contact), - onLongPress: () => _showMessageActions(message, contact), - ); - }, + return Builder( + builder: (context) { + final textScale = context.select( + (service) => service.scale, + ); + return _MessageBubble( + message: message, + senderName: widget.contact.type == advTypeRoom + ? "${contact.name} [$fourByteHex]" + : contact.name, + isRoomServer: widget.contact.type == advTypeRoom, + textScale: textScale, + onTap: () => _openMessagePath(message, contact), + onLongPress: () => _showMessageActions(message, contact), + ); + }, + ); + }, + ), ); } @@ -1163,11 +1175,13 @@ class _MessageBubble extends StatelessWidget { final bool isRoomServer; final VoidCallback? onTap; final VoidCallback? onLongPress; + final double textScale; const _MessageBubble({ required this.message, required this.senderName, required this.isRoomServer, + required this.textScale, this.onTap, this.onLongPress, }); @@ -1190,6 +1204,7 @@ class _MessageBubble extends StatelessWidget { ? colorScheme.onErrorContainer : (isOutgoing ? colorScheme.onPrimary : colorScheme.onSurface); final metaColor = textColor.withValues(alpha: 0.7); + const bodyFontSize = 14.0; String messageText = message.text; if (isRoomServer && !isOutgoing) { messageText = message.text.substring(4.clamp(0, message.text.length)); @@ -1258,6 +1273,7 @@ class _MessageBubble extends StatelessWidget { poi, textColor, metaColor, + textScale, trailing: (!enableTracing && isOutgoing) ? Padding( padding: const EdgeInsets.only(bottom: 2), @@ -1321,10 +1337,14 @@ class _MessageBubble extends StatelessWidget { Flexible( child: Linkify( text: messageText, - style: TextStyle(color: textColor), - linkStyle: const TextStyle( + style: TextStyle( + color: textColor, + fontSize: bodyFontSize * textScale, + ), + linkStyle: TextStyle( color: Colors.green, decoration: TextDecoration.underline, + fontSize: bodyFontSize * textScale, ), options: const LinkifyOptions( humanize: false, @@ -1464,7 +1484,8 @@ class _MessageBubble extends StatelessWidget { BuildContext context, _PoiInfo poi, Color textColor, - Color metaColor, { + Color metaColor, + double textScale, { Widget? trailing, }) { return Row( @@ -1493,12 +1514,16 @@ class _MessageBubble extends StatelessWidget { children: [ Text( context.l10n.chat_poiShared, - style: TextStyle(color: textColor, fontWeight: FontWeight.w600), + style: TextStyle( + color: textColor, + fontWeight: FontWeight.w600, + fontSize: 14 * textScale, + ), ), if (poi.label.isNotEmpty) Text( poi.label, - style: TextStyle(color: metaColor, fontSize: 12), + style: TextStyle(color: metaColor, fontSize: 12 * textScale), ), ], ), diff --git a/lib/services/chat_text_scale_service.dart b/lib/services/chat_text_scale_service.dart new file mode 100644 index 0000000..0257a56 --- /dev/null +++ b/lib/services/chat_text_scale_service.dart @@ -0,0 +1,45 @@ +import 'package:flutter/foundation.dart'; + +import '../storage/prefs_manager.dart'; + +/// Client-side accessibility/UI service that exposes a persistent shared text scale +/// factor. No MeshCoreConnector/RoomServer or protocol interaction occurs, and the +/// value is saved locally via SharedPreferences so it can be reused in Markdown +/// viewers, log panels, or other text-heavy widgets without redundant network +/// dependencies. +/// +/// Widgets should scope rebuilds using the snippet below so only the scaled text +/// is rebuilt instead of the entire chat list: +/// ```dart +/// context.select( +/// (service) => service.scale, +/// ) +/// ``` +class ChatTextScaleService extends ChangeNotifier { + static const _prefKey = 'chat_text_scale'; + static const double _minScale = 0.8; + static const double _maxScale = 1.8; + + double _scale = 1.0; + + double get scale => _scale; + + Future initialize() async { + final stored = PrefsManager.instance.getDouble(_prefKey); + if (stored != null) { + _scale = _clamp(stored); + } + } + + void setScale(double value) { + final next = _clamp(value); + if (next == _scale) return; + _scale = next; + PrefsManager.instance.setDouble(_prefKey, _scale); + notifyListeners(); + } + + void reset() => setScale(1.0); + + double _clamp(double value) => value.clamp(_minScale, _maxScale).toDouble(); +} diff --git a/lib/widgets/chat_zoom_wrapper.dart b/lib/widgets/chat_zoom_wrapper.dart new file mode 100644 index 0000000..e18662d --- /dev/null +++ b/lib/widgets/chat_zoom_wrapper.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../services/chat_text_scale_service.dart'; + +/// Gesture wrapper that exposes two-finger pinch-to-zoom for chat scrollables. +/// Double-tap resets the scale. Only the wrapper itself listens to gestures; +/// child scrollables keep their normal touch handling. +class ChatZoomWrapper extends StatelessWidget { + ChatZoomWrapper({super.key, required this.child, this.onDoubleTap}); + + final Widget child; + final VoidCallback? onDoubleTap; + final _ZoomGestureState _state = _ZoomGestureState(); + + @override + Widget build(BuildContext context) { + final service = context.read(); + + return GestureDetector( + behavior: HitTestBehavior.translucent, + onDoubleTap: () { + service.reset(); + onDoubleTap?.call(); + }, + onScaleStart: (details) { + if (details.pointerCount != 2) return; + _state.startScale = service.scale; + }, + onScaleUpdate: (details) { + if (details.pointerCount != 2) return; + final baseScale = _state.startScale ?? service.scale; + service.setScale(baseScale * details.scale); + }, + onScaleEnd: (_) { + _state.startScale = null; + }, + child: child, + ); + } +} + +class _ZoomGestureState { + double? startScale; +} From 8a160246424023f76969f33e5bbd6e937e7c47d1 Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 23:06:27 -0500 Subject: [PATCH 30/34] fix(chat): stabilize pinch-to-zoom scaling --- lib/services/chat_text_scale_service.dart | 33 ++++++++++++++++++++--- lib/widgets/chat_zoom_wrapper.dart | 28 ++++++++++--------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/lib/services/chat_text_scale_service.dart b/lib/services/chat_text_scale_service.dart index 0257a56..21d6a5f 100644 --- a/lib/services/chat_text_scale_service.dart +++ b/lib/services/chat_text_scale_service.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/foundation.dart'; import '../storage/prefs_manager.dart'; @@ -21,6 +23,7 @@ class ChatTextScaleService extends ChangeNotifier { static const double _maxScale = 1.8; double _scale = 1.0; + Timer? _saveTimer; double get scale => _scale; @@ -31,15 +34,39 @@ class ChatTextScaleService extends ChangeNotifier { } } - void setScale(double value) { + void setScale(double value, {bool persistImmediately = false}) { final next = _clamp(value); if (next == _scale) return; _scale = next; - PrefsManager.instance.setDouble(_prefKey, _scale); notifyListeners(); + if (persistImmediately) { + _commitScale(); + } else { + _scheduleSave(); + } } - void reset() => setScale(1.0); + void reset() { + setScale(1.0, persistImmediately: true); + } + + void persist() => _commitScale(); + + @override + void dispose() { + _saveTimer?.cancel(); + super.dispose(); + } + + void _scheduleSave() { + _saveTimer?.cancel(); + _saveTimer = Timer(const Duration(milliseconds: 250), _commitScale); + } + + void _commitScale() { + _saveTimer?.cancel(); + PrefsManager.instance.setDouble(_prefKey, _scale); + } double _clamp(double value) => value.clamp(_minScale, _maxScale).toDouble(); } diff --git a/lib/widgets/chat_zoom_wrapper.dart b/lib/widgets/chat_zoom_wrapper.dart index e18662d..f0c6815 100644 --- a/lib/widgets/chat_zoom_wrapper.dart +++ b/lib/widgets/chat_zoom_wrapper.dart @@ -6,12 +6,18 @@ import '../services/chat_text_scale_service.dart'; /// Gesture wrapper that exposes two-finger pinch-to-zoom for chat scrollables. /// Double-tap resets the scale. Only the wrapper itself listens to gestures; /// child scrollables keep their normal touch handling. -class ChatZoomWrapper extends StatelessWidget { - ChatZoomWrapper({super.key, required this.child, this.onDoubleTap}); +class ChatZoomWrapper extends StatefulWidget { + const ChatZoomWrapper({super.key, required this.child, this.onDoubleTap}); final Widget child; final VoidCallback? onDoubleTap; - final _ZoomGestureState _state = _ZoomGestureState(); + + @override + State createState() => _ChatZoomWrapperState(); +} + +class _ChatZoomWrapperState extends State { + double? _startScale; @override Widget build(BuildContext context) { @@ -21,25 +27,23 @@ class ChatZoomWrapper extends StatelessWidget { behavior: HitTestBehavior.translucent, onDoubleTap: () { service.reset(); - onDoubleTap?.call(); + service.persist(); + widget.onDoubleTap?.call(); }, onScaleStart: (details) { if (details.pointerCount != 2) return; - _state.startScale = service.scale; + _startScale = service.scale; }, onScaleUpdate: (details) { if (details.pointerCount != 2) return; - final baseScale = _state.startScale ?? service.scale; + final baseScale = _startScale ?? service.scale; service.setScale(baseScale * details.scale); }, onScaleEnd: (_) { - _state.startScale = null; + _startScale = null; + service.persist(); }, - child: child, + child: widget.child, ); } } - -class _ZoomGestureState { - double? startScale; -} From 2a7cc28a3a5410417d1310fce0e204115048511f Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Mon, 23 Feb 2026 23:46:25 -0500 Subject: [PATCH 31/34] fix --- lib/l10n/app_bg.arb | 2 +- lib/l10n/app_de.arb | 2 +- lib/l10n/app_es.arb | 2 +- lib/l10n/app_fr.arb | 2 +- lib/l10n/app_it.arb | 2 +- lib/l10n/app_nl.arb | 2 +- lib/l10n/app_pl.arb | 2 +- lib/l10n/app_pt.arb | 2 +- lib/l10n/app_ru.arb | 2 +- lib/l10n/app_sk.arb | 2 +- lib/l10n/app_sl.arb | 2 +- lib/l10n/app_sv.arb | 2 +- lib/l10n/app_uk.arb | 2 +- lib/l10n/app_zh.arb | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 96db350..b59d407 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Неуспешно изтриване на канала \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "bg", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 3898e76..409bdbb 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Kanal {name} konnte nicht gelöscht werden", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "de", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index e07b48b..9e03138 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "No se pudo eliminar el canal \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "es", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index f3c79bf..78c155c 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Échec de la suppression de la chaîne \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "fr", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 2266641..a6871a1 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Impossibile eliminare il canale \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "it", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index ab57355..57797f9 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Kan kanaal {name} niet verwijderen", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "nl", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index d16052d..908892e 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Nie udało się usunąć kanału \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "pl", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 8d4e827..d221ae5 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Falha ao excluir o canal \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "pt", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 3d17889..eb6627c 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Не удалось удалить канал {name}.", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "ru", diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index c87ef14..2e7a06b 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Kanál \"{name}\" sa nepodarilo odstrániť", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sk", diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index b0fc948..5b0cbfb 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Kanala {name} ni bilo mogoče izbrisati", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sl", diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 7806ed7..7cec9b7 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Det gick inte att ta bort kanalen \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "sv", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index b990b14..2ad9dde 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "Не вдалося видалити канал \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "uk", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 295274d..43adb81 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,4 +1,4 @@ -{ +{ "channels_channelDeleteFailed": "无法删除频道 \"{name}\"", "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, "@@locale": "zh", From c880c2d107c6cbc85c4ba39fb25d4d452a62f5ff Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Tue, 24 Feb 2026 00:02:10 -0500 Subject: [PATCH 32/34] fix channel actions context --- lib/screens/channels_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index d2a2e3d..582fee7 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -522,7 +522,7 @@ class _ChannelsScreenState extends State : context.l10n.channels_muteChannel, ), onTap: () async { - Navigator.pop(context); + Navigator.pop(sheetContext); if (isMuted) { await settingsService.unmuteChannel(channel.name); } else { From 515b9c1f295220b51641a7e8587c514ce27948de Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:51:58 -0500 Subject: [PATCH 33/34] fix los init localization --- lib/screens/line_of_sight_map_screen.dart | 12 +++++++++++- pubspec.lock | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 0fbc21b..402b417 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -73,6 +73,7 @@ class _LineOfSightMapScreenState extends State { bool _showMarkerLabels = true; bool _didReceivePositionUpdate = false; int _losRequestNonce = 0; + bool _initialLosScheduled = false; @override void initState() { @@ -83,7 +84,16 @@ class _LineOfSightMapScreenState extends State { _end = widget.candidates[1]; } } - _runLos(); + _scheduleInitialRun(); + } + + void _scheduleInitialRun() { + if (_initialLosScheduled) return; + _initialLosScheduled = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + _runLos(); + }); } @override diff --git a/pubspec.lock b/pubspec.lock index aa8819e..fa23b27 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1140,4 +1140,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" \ No newline at end of file + flutter: ">=3.38.4" From 31db565ebfa5ccd967fb1f82b4b7a0749b65097f Mon Sep 17 00:00:00 2001 From: just_stuff_tm <133525672+just-stuff-tm@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:54:03 -0500 Subject: [PATCH 34/34] PR Combined #228 #220 #219 #201 --- lib/screens/line_of_sight_map_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/line_of_sight_map_screen.dart b/lib/screens/line_of_sight_map_screen.dart index 402b417..ec8a391 100644 --- a/lib/screens/line_of_sight_map_screen.dart +++ b/lib/screens/line_of_sight_map_screen.dart @@ -122,7 +122,7 @@ class _LineOfSightMapScreenState extends State { }); try { - final connector = context.watch(); + final connector = context.read(); final frequencyMHz = _normalizeFrequencyMHz(connector.currentFreqHz); final result = await _lineOfSightService.analyzePath( [start.point, end.point],