2025-12-26 13:33:03 -07:00
|
|
|
import 'dart:math';
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_map/flutter_map.dart';
|
|
|
|
|
import 'package:latlong2/latlong.dart';
|
2026-02-08 11:32:36 -08:00
|
|
|
import 'package:meshcore_open/screens/path_trace_map.dart';
|
2025-12-26 13:33:03 -07:00
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
|
|
import '../connector/meshcore_connector.dart';
|
2025-12-27 15:32:32 -07:00
|
|
|
import '../services/map_tile_cache_service.dart';
|
2026-02-21 01:08:23 -05:00
|
|
|
import '../services/app_settings_service.dart';
|
2025-12-26 13:33:03 -07:00
|
|
|
import '../connector/meshcore_protocol.dart';
|
2026-01-11 17:13:50 -07:00
|
|
|
import '../l10n/app_localizations.dart';
|
|
|
|
|
import '../l10n/l10n.dart';
|
2025-12-26 13:33:03 -07:00
|
|
|
import '../models/channel_message.dart';
|
2026-02-21 01:08:23 -05:00
|
|
|
import '../models/app_settings.dart';
|
2025-12-26 13:33:03 -07:00
|
|
|
import '../models/contact.dart';
|
2026-02-21 01:08:23 -05:00
|
|
|
import '../widgets/adaptive_app_bar_title.dart';
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
class ChannelMessagePathScreen extends StatelessWidget {
|
|
|
|
|
final ChannelMessage message;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
final bool channelMessage;
|
|
|
|
|
const ChannelMessagePathScreen({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.message,
|
|
|
|
|
this.channelMessage = false,
|
|
|
|
|
});
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Consumer<MeshCoreConnector>(
|
|
|
|
|
builder: (context, connector, _) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final l10n = context.l10n;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
final primaryPathTmp = _selectPrimaryPath(
|
2026-02-04 08:32:35 -08:00
|
|
|
message.pathBytes,
|
|
|
|
|
message.pathVariants,
|
|
|
|
|
);
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
|
|
|
|
final primaryPath = !channelMessage && !message.isOutgoing
|
|
|
|
|
? Uint8List.fromList(primaryPathTmp.reversed.toList())
|
|
|
|
|
: primaryPathTmp;
|
2026-03-17 21:56:42 +01:00
|
|
|
final hops = _buildPathHops(primaryPath, connector, l10n);
|
2025-12-27 15:32:32 -07:00
|
|
|
final hasHopDetails = primaryPath.isNotEmpty;
|
|
|
|
|
final observedLabel = _formatObservedHops(
|
|
|
|
|
primaryPath.length,
|
|
|
|
|
message.pathLength,
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n,
|
2025-12-27 15:32:32 -07:00
|
|
|
);
|
|
|
|
|
final extraPaths = _otherPaths(primaryPath, message.pathVariants);
|
2025-12-26 13:33:03 -07:00
|
|
|
return Scaffold(
|
|
|
|
|
appBar: AppBar(
|
2026-02-21 01:08:23 -05:00
|
|
|
title: AdaptiveAppBarTitle(l10n.channelPath_title),
|
2025-12-26 13:33:03 -07:00
|
|
|
actions: [
|
2026-02-08 11:32:36 -08:00
|
|
|
IconButton(
|
|
|
|
|
icon: const Icon(Icons.radar_outlined),
|
|
|
|
|
tooltip: l10n.channelPath_viewMap,
|
|
|
|
|
onPressed: () => Navigator.push(
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => PathTraceMapScreen(
|
|
|
|
|
title: context.l10n.contacts_repeaterPathTrace,
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
path: primaryPath,
|
2026-03-14 17:51:24 -07:00
|
|
|
flipPathAround: true,
|
|
|
|
|
reversePathAround:
|
|
|
|
|
!(!channelMessage && !message.isOutgoing),
|
2026-03-23 19:26:05 -07:00
|
|
|
pathHashByteWidth: context
|
|
|
|
|
.read<MeshCoreConnector>()
|
|
|
|
|
.pathHashByteWidth,
|
2026-02-08 11:32:36 -08:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2025-12-26 13:33:03 -07:00
|
|
|
IconButton(
|
|
|
|
|
icon: const Icon(Icons.map_outlined),
|
2026-01-11 17:13:50 -07:00
|
|
|
tooltip: l10n.channelPath_viewMap,
|
2025-12-26 13:33:03 -07:00
|
|
|
onPressed: hasHopDetails
|
|
|
|
|
? () {
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
_openPathMap(context, channelMessage: channelMessage);
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
: null,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
body: SafeArea(
|
|
|
|
|
top: false,
|
|
|
|
|
child: ListView(
|
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
|
children: [
|
|
|
|
|
_buildSummaryCard(context, observedLabel: observedLabel),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
if (extraPaths.isNotEmpty) ...[
|
|
|
|
|
Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n.channelPath_otherObservedPaths,
|
2025-12-29 20:01:16 -07:00
|
|
|
style: Theme.of(context).textTheme.titleSmall,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
|
_buildPathVariants(context, extraPaths),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
],
|
2025-12-27 15:32:32 -07:00
|
|
|
Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n.channelPath_repeaterHops,
|
2025-12-27 15:32:32 -07:00
|
|
|
style: Theme.of(context).textTheme.titleSmall,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 8),
|
2025-12-29 20:01:16 -07:00
|
|
|
if (!hasHopDetails)
|
2026-01-11 17:13:50 -07:00
|
|
|
Text(
|
|
|
|
|
l10n.channelPath_noHopDetails,
|
|
|
|
|
style: const TextStyle(color: Colors.grey),
|
2025-12-29 20:01:16 -07:00
|
|
|
)
|
|
|
|
|
else
|
2026-01-11 17:13:50 -07:00
|
|
|
..._buildHopTiles(context, hops),
|
2025-12-27 15:32:32 -07:00
|
|
|
],
|
2025-12-29 20:01:16 -07:00
|
|
|
),
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 08:32:35 -08:00
|
|
|
Widget _buildSummaryCard(BuildContext context, {String? observedLabel}) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final l10n = context.l10n;
|
2025-12-26 13:33:03 -07:00
|
|
|
return Card(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.all(12),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n.channelPath_messageDetails,
|
2025-12-26 13:33:03 -07:00
|
|
|
style: Theme.of(context).textTheme.titleSmall,
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 8),
|
2026-01-11 17:13:50 -07:00
|
|
|
_buildDetailRow(l10n.channelPath_senderLabel, message.senderName),
|
2026-02-04 08:32:35 -08:00
|
|
|
_buildDetailRow(
|
|
|
|
|
l10n.channelPath_timeLabel,
|
|
|
|
|
_formatTime(message.timestamp, l10n),
|
|
|
|
|
),
|
2025-12-26 13:33:03 -07:00
|
|
|
if (message.repeatCount > 0)
|
2026-02-04 08:32:35 -08:00
|
|
|
_buildDetailRow(
|
|
|
|
|
l10n.channelPath_repeatsLabel,
|
|
|
|
|
message.repeatCount.toString(),
|
|
|
|
|
),
|
|
|
|
|
_buildDetailRow(
|
|
|
|
|
l10n.channelPath_pathLabelTitle,
|
|
|
|
|
_formatPathLabel(message.pathLength, l10n),
|
|
|
|
|
),
|
|
|
|
|
if (observedLabel != null)
|
|
|
|
|
_buildDetailRow(l10n.channelPath_observedLabel, observedLabel),
|
2025-12-26 13:33:03 -07:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 08:32:35 -08:00
|
|
|
Widget _buildPathVariants(BuildContext context, List<Uint8List> variants) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final l10n = context.l10n;
|
2025-12-27 15:32:32 -07:00
|
|
|
return Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
for (int i = 0; i < variants.length; i++)
|
|
|
|
|
Card(
|
|
|
|
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
|
|
|
|
child: ListTile(
|
|
|
|
|
dense: true,
|
|
|
|
|
title: Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n.channelPath_observedPathTitle(
|
|
|
|
|
i + 1,
|
|
|
|
|
_formatHopCount(variants[i].length, l10n),
|
|
|
|
|
),
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
|
|
|
|
subtitle: Text(_formatPathPrefixes(variants[i])),
|
|
|
|
|
trailing: const Icon(Icons.map_outlined, size: 20),
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
onTap: () => _openPathMap(
|
|
|
|
|
context,
|
|
|
|
|
initialPath: variants[i],
|
|
|
|
|
channelMessage: channelMessage,
|
|
|
|
|
),
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
List<Widget> _buildHopTiles(BuildContext context, List<_PathHop> hops) {
|
|
|
|
|
final l10n = context.l10n;
|
2025-12-26 13:33:03 -07:00
|
|
|
return [
|
|
|
|
|
for (final hop in hops)
|
|
|
|
|
Card(
|
|
|
|
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
|
|
|
|
child: ListTile(
|
|
|
|
|
dense: true,
|
|
|
|
|
leading: CircleAvatar(
|
|
|
|
|
radius: 14,
|
|
|
|
|
child: Text(
|
|
|
|
|
hop.index.toString(),
|
|
|
|
|
style: const TextStyle(fontSize: 12),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
title: Text(hop.displayLabel),
|
|
|
|
|
subtitle: Text(
|
|
|
|
|
hop.hasLocation
|
|
|
|
|
? '${hop.position!.latitude.toStringAsFixed(5)}, '
|
2026-02-04 08:32:35 -08:00
|
|
|
'${hop.position!.longitude.toStringAsFixed(5)}'
|
2026-01-11 17:13:50 -07:00
|
|
|
: l10n.channelPath_noLocationData,
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
String _formatTime(DateTime time, AppLocalizations l10n) {
|
2025-12-26 13:33:03 -07:00
|
|
|
final now = DateTime.now();
|
|
|
|
|
final diff = now.difference(time);
|
|
|
|
|
|
|
|
|
|
if (diff.inDays > 0) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final timeLabel =
|
2025-12-26 13:33:03 -07:00
|
|
|
'${time.hour}:${time.minute.toString().padLeft(2, '0')}';
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.channelPath_timeWithDate(time.day, time.month, timeLabel);
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.channelPath_timeOnly(
|
|
|
|
|
'${time.hour}:${time.minute.toString().padLeft(2, '0')}',
|
|
|
|
|
);
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
String _formatPathLabel(int? pathLength, AppLocalizations l10n) {
|
|
|
|
|
if (pathLength == null) return l10n.channelPath_unknownPath;
|
|
|
|
|
if (pathLength < 0) return l10n.channelPath_floodPath;
|
|
|
|
|
if (pathLength == 0) return l10n.channelPath_directPath;
|
|
|
|
|
return l10n.chat_hopsCount(pathLength);
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
String? _formatObservedHops(
|
|
|
|
|
int observedCount,
|
|
|
|
|
int? pathLength,
|
|
|
|
|
AppLocalizations l10n,
|
|
|
|
|
) {
|
2025-12-27 15:32:32 -07:00
|
|
|
if (observedCount <= 0 && (pathLength == null || pathLength <= 0)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (pathLength == null || pathLength < 0) {
|
2026-01-11 17:13:50 -07:00
|
|
|
return observedCount > 0 ? l10n.chat_hopsCount(observedCount) : null;
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
|
|
|
|
if (observedCount == 0) {
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.channelPath_observedZeroOf(pathLength);
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
|
|
|
|
if (observedCount == pathLength) {
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.chat_hopsCount(observedCount);
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.channelPath_observedSomeOf(observedCount, pathLength);
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
|
|
|
|
|
2025-12-26 13:33:03 -07:00
|
|
|
Widget _buildDetailRow(String label, String value) {
|
|
|
|
|
return Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
|
|
|
child: Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: 70,
|
|
|
|
|
child: Text(label, style: TextStyle(color: Colors.grey[600])),
|
|
|
|
|
),
|
|
|
|
|
Expanded(child: Text(value)),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-12-27 15:32:32 -07:00
|
|
|
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
void _openPathMap(
|
|
|
|
|
BuildContext context, {
|
|
|
|
|
Uint8List? initialPath,
|
|
|
|
|
bool channelMessage = false,
|
|
|
|
|
}) {
|
2025-12-27 15:32:32 -07:00
|
|
|
Navigator.push(
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => ChannelMessagePathMapScreen(
|
|
|
|
|
message: message,
|
|
|
|
|
initialPath: initialPath,
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
channelMessage: channelMessage,
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
class ChannelMessagePathMapScreen extends StatefulWidget {
|
2025-12-26 13:33:03 -07:00
|
|
|
final ChannelMessage message;
|
2025-12-27 15:32:32 -07:00
|
|
|
final Uint8List? initialPath;
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
final bool channelMessage;
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
const ChannelMessagePathMapScreen({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.message,
|
2025-12-27 15:32:32 -07:00
|
|
|
this.initialPath,
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
this.channelMessage = false,
|
2025-12-26 13:33:03 -07:00
|
|
|
});
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
@override
|
|
|
|
|
State<ChannelMessagePathMapScreen> createState() =>
|
|
|
|
|
_ChannelMessagePathMapScreenState();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 08:32:35 -08:00
|
|
|
class _ChannelMessagePathMapScreenState
|
|
|
|
|
extends State<ChannelMessagePathMapScreen> {
|
2026-02-21 01:08:23 -05:00
|
|
|
static const double _labelZoomThreshold = 8.5;
|
|
|
|
|
|
2026-03-17 23:22:23 +01:00
|
|
|
final MapController _mapController = MapController();
|
2025-12-27 15:32:32 -07:00
|
|
|
Uint8List? _selectedPath;
|
2026-02-08 11:32:36 -08:00
|
|
|
double _pathDistance = 0.0;
|
2026-02-21 01:08:23 -05:00
|
|
|
bool _showNodeLabels = true;
|
|
|
|
|
bool _didReceivePositionUpdate = false;
|
2026-03-17 23:22:23 +01:00
|
|
|
int? _focusedHopIndex;
|
2025-12-27 15:32:32 -07:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
_selectedPath = widget.initialPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void didUpdateWidget(ChannelMessagePathMapScreen oldWidget) {
|
|
|
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
|
if (oldWidget.message != widget.message ||
|
2026-02-04 08:32:35 -08:00
|
|
|
!_pathsEqual(
|
|
|
|
|
oldWidget.initialPath ?? Uint8List(0),
|
|
|
|
|
widget.initialPath ?? Uint8List(0),
|
|
|
|
|
)) {
|
2025-12-27 15:32:32 -07:00
|
|
|
_selectedPath = widget.initialPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 11:32:36 -08:00
|
|
|
double _getPathDistance(List<LatLng> points) {
|
|
|
|
|
double totalDistance = 0.0;
|
|
|
|
|
final distanceCalculator = Distance();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < points.length - 1; i++) {
|
|
|
|
|
totalDistance += distanceCalculator(points[i], points[i + 1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return totalDistance;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 23:22:23 +01:00
|
|
|
void _focusHop(_PathHop hop) {
|
|
|
|
|
if (!hop.hasLocation) return;
|
|
|
|
|
final targetZoom = _didReceivePositionUpdate
|
2026-03-18 06:52:08 +01:00
|
|
|
? max(_mapController.camera.zoom, 10.0)
|
|
|
|
|
: 12.0;
|
2026-03-17 23:22:23 +01:00
|
|
|
_mapController.move(hop.position!, targetZoom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _onHopTapped(_PathHop hop) {
|
|
|
|
|
_focusHop(hop);
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
setState(() {
|
|
|
|
|
_focusedHopIndex = hop.index;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-26 13:33:03 -07:00
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Consumer<MeshCoreConnector>(
|
|
|
|
|
builder: (context, connector, _) {
|
2026-02-21 01:08:23 -05:00
|
|
|
final settings = context.watch<AppSettingsService>().settings;
|
|
|
|
|
final isImperial = settings.unitSystem == UnitSystem.imperial;
|
2025-12-27 15:32:32 -07:00
|
|
|
final tileCache = context.read<MapTileCacheService>();
|
2026-02-04 08:32:35 -08:00
|
|
|
final primaryPath = _selectPrimaryPath(
|
|
|
|
|
widget.message.pathBytes,
|
|
|
|
|
widget.message.pathVariants,
|
|
|
|
|
);
|
|
|
|
|
final observedPaths = _buildObservedPaths(
|
|
|
|
|
primaryPath,
|
|
|
|
|
widget.message.pathVariants,
|
|
|
|
|
);
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
final selectedPathTmp = _resolveSelectedPath(
|
2025-12-27 15:32:32 -07:00
|
|
|
_selectedPath,
|
|
|
|
|
observedPaths,
|
|
|
|
|
primaryPath,
|
|
|
|
|
);
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
|
|
|
|
final selectedPath =
|
|
|
|
|
((!widget.message.isOutgoing && !widget.channelMessage) ||
|
|
|
|
|
(widget.message.isOutgoing && widget.channelMessage))
|
|
|
|
|
? Uint8List.fromList(selectedPathTmp.reversed.toList())
|
|
|
|
|
: selectedPathTmp;
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
final selectedIndex = _indexForPath(selectedPath, observedPaths);
|
2026-03-26 16:46:01 -07:00
|
|
|
final hops = _buildPathHops(selectedPath, connector, context.l10n);
|
2026-02-08 11:32:36 -08:00
|
|
|
|
|
|
|
|
final points = <LatLng>[];
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
|
|
|
|
if ((widget.message.isOutgoing && !widget.channelMessage) ||
|
|
|
|
|
(widget.message.isOutgoing && widget.channelMessage)) {
|
|
|
|
|
points.add(LatLng(connector.selfLatitude!, connector.selfLongitude!));
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 11:32:36 -08:00
|
|
|
for (final hop in hops) {
|
|
|
|
|
if (hop.hasLocation) {
|
|
|
|
|
points.add(hop.position!);
|
|
|
|
|
}
|
|
|
|
|
}
|
Add a signal readout for the nearest repeater. With improvements to app bar and other UI polish. (#200)
* Refactor Cayenne LPP parsing with error handling and logging
- Added error handling and logging to the Cayenne LPP parsing methods to manage malformed data gracefully.
- Improved the structure of the parsing logic for better readability and maintainability.
- Updated the Contact model to include error handling during frame parsing.
- Refactored Channels, Contacts, Map, and Neighbours screens to utilize a new AppBarTitle widget for consistent app bar design.
- Enhanced the BatteryIndicator widget to display SNR information for direct repeaters.
- Introduced SNRUi class for better management of SNR icon and text representation.
- Improved error handling in PathTraceMap and Neighbours screens to log errors appropriately.
* Fix trace route bytes generation logic in Contact model
* Ignore advertisements from self in MeshCoreConnector
* Refactor PathTraceData to use List<double> for snrData and adjust data mapping in PathTraceMapScreen
* Add SNRIndicator to AppBar and refactor BatteryIndicator layout
* Enhance path management dialog to display direct repeaters with color coding based on signal strength
* Remove unused import from SNR indicator widget
* Update lib/models/contact.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/connector/meshcore_connector.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/screens/path_trace_map.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/widgets/battery_indicator.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update lib/helpers/cayenne_lpp.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor packet handling to skip only the RSSI byte for improved reliability
* Add SNR indicator localization and update UI references for nearby repeaters
* Handle loading state and error parsing in PathTraceMapScreen; update SNR indicator dialog content layout
* Throw an exception for unsupported LPP types in CayenneLpp class
* Refactor AppBarTitle widget to remove unused style parameter; update related screens to reflect changes
Improve SNR handling by adding validation for spreading factor range in snrUiFromSNR function
Update contact handling in MeshCoreConnector to fix variable naming and improve readability
Stop parsing unsupported LPP types in CayenneLpp to avoid misalignment
* Sort direct repeaters by last updated time and SNR; limit to top three for improved path management dialog
* Prevent notifications for chat and sensor adverts without a valid path
* Implement ranking system for direct repeaters based on SNR and recency; update related UI components to reflect changes
* Refactor localization keys for "neighbors" terminology across multiple languages
- Updated localization keys from "neighbours" to "neighbors" in the following files:
- app_localizations_bg.dart
- app_localizations_de.dart
- app_localizations_en.dart
- app_localizations_es.dart
- app_localizations_fr.dart
- app_localizations_it.dart
- app_localizations_nl.dart
- app_localizations_pl.dart
- app_localizations_pt.dart
- app_localizations_ru.dart
- app_localizations_sk.dart
- app_localizations_sl.dart
- app_localizations_sv.dart
- app_localizations_uk.dart
- app_localizations_zh.dart
- Updated corresponding ARB files to reflect the changes in keys.
- Renamed the NeighboursScreen to NeighborsScreen in the chat and repeater hub screens for consistency.
* Adjust ranking calculation for direct repeaters by adding offset to SNR for improved accuracy
* Fix typo in variable name for second direct repeater in path management dialog
* Refactor ranking calculation for direct repeaters and update path handling in channel message screens
* Refactor path handling in ChannelMessagePathScreen to improve logic for outgoing messages and channel messages
* Fix AppBarTitle horizontal overflow with long titles (#187)
* Initial plan
* Wrap title Column in Expanded to prevent horizontal overflow in AppBarTitle
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
* Refactor AppBarTitle widget to simplify Text widget initialization
* Add "Show All Paths" feature to chat path management
- Implemented localization for "Show All Paths" in multiple languages (DE, EN, ES, FR, IT, NL, PL, PT, RU, SK, SL, SV, UK, ZH).
- Updated path management dialog to include a toggle for showing all paths.
- Refactored path history display logic to conditionally show paths based on the toggle state.
- Cleaned up unused print statements and improved code readability in path tracing and chat screens.
* Refactor FeatureToggleRow visibility in chat and path management dialogs based on repeaters list
* Remove unused import of 'dart:ffi' in path_trace_map.dart
* Refactor repeater management logic and update UI state handling in chat and path management dialogs
* Refactor RX data handling and improve repeater management logic in chat and path management dialogs
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wel97459 <12990640+wel97459@users.noreply.github.com>
2026-02-20 20:27:38 -08:00
|
|
|
|
|
|
|
|
if ((!widget.message.isOutgoing && !widget.channelMessage) ||
|
|
|
|
|
(!widget.message.isOutgoing && widget.channelMessage)) {
|
|
|
|
|
points.add(LatLng(connector.selfLatitude!, connector.selfLongitude!));
|
|
|
|
|
}
|
2026-02-08 11:32:36 -08:00
|
|
|
|
2025-12-26 13:33:03 -07:00
|
|
|
final polylines = points.length > 1
|
|
|
|
|
? [
|
|
|
|
|
Polyline(
|
|
|
|
|
points: points,
|
|
|
|
|
strokeWidth: 4,
|
|
|
|
|
color: Colors.blueAccent,
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
: <Polyline>[];
|
|
|
|
|
|
2026-02-04 08:32:35 -08:00
|
|
|
final initialCenter = points.isNotEmpty
|
|
|
|
|
? points.first
|
|
|
|
|
: const LatLng(0, 0);
|
2025-12-26 13:33:03 -07:00
|
|
|
final initialZoom = points.isNotEmpty ? 13.0 : 2.0;
|
2026-02-21 01:08:23 -05:00
|
|
|
if (!_didReceivePositionUpdate) {
|
|
|
|
|
_showNodeLabels = initialZoom >= _labelZoomThreshold;
|
|
|
|
|
}
|
2026-02-04 08:32:35 -08:00
|
|
|
final bounds = points.length > 1
|
|
|
|
|
? LatLngBounds.fromPoints(points)
|
|
|
|
|
: null;
|
2026-02-08 11:32:36 -08:00
|
|
|
final mapKey = ValueKey(
|
|
|
|
|
'${_formatPathPrefixes(selectedPath)},${context.l10n.pathTrace_you}',
|
|
|
|
|
);
|
|
|
|
|
_pathDistance = _getPathDistance(points);
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
return Scaffold(
|
2026-02-21 01:08:23 -05:00
|
|
|
appBar: AppBar(
|
|
|
|
|
title: AdaptiveAppBarTitle(context.l10n.channelPath_mapTitle),
|
|
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
body: SafeArea(
|
|
|
|
|
top: false,
|
|
|
|
|
child: Stack(
|
|
|
|
|
children: [
|
|
|
|
|
FlutterMap(
|
|
|
|
|
key: mapKey,
|
2026-03-17 23:22:23 +01:00
|
|
|
mapController: _mapController,
|
2025-12-29 20:01:16 -07:00
|
|
|
options: MapOptions(
|
|
|
|
|
initialCenter: initialCenter,
|
|
|
|
|
initialZoom: initialZoom,
|
|
|
|
|
initialCameraFit: bounds == null
|
|
|
|
|
? null
|
|
|
|
|
: CameraFit.bounds(
|
|
|
|
|
bounds: bounds,
|
|
|
|
|
padding: const EdgeInsets.all(64),
|
|
|
|
|
maxZoom: 16,
|
|
|
|
|
),
|
|
|
|
|
minZoom: 2.0,
|
|
|
|
|
maxZoom: 18.0,
|
2026-02-05 09:24:24 -08:00
|
|
|
interactionOptions: InteractionOptions(
|
|
|
|
|
flags: ~InteractiveFlag.rotate,
|
|
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
onPositionChanged: (camera, hasGesture) {
|
|
|
|
|
final shouldShow = camera.zoom >= _labelZoomThreshold;
|
|
|
|
|
if (!_didReceivePositionUpdate ||
|
|
|
|
|
shouldShow != _showNodeLabels) {
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
setState(() {
|
|
|
|
|
_didReceivePositionUpdate = true;
|
|
|
|
|
_showNodeLabels = shouldShow;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
children: [
|
|
|
|
|
TileLayer(
|
|
|
|
|
urlTemplate: kMapTileUrlTemplate,
|
|
|
|
|
tileProvider: tileCache.tileProvider,
|
|
|
|
|
userAgentPackageName:
|
|
|
|
|
MapTileCacheService.userAgentPackageName,
|
|
|
|
|
maxZoom: 19,
|
|
|
|
|
),
|
2026-02-04 08:32:35 -08:00
|
|
|
if (polylines.isNotEmpty)
|
|
|
|
|
PolylineLayer(polylines: polylines),
|
2026-02-21 01:08:23 -05:00
|
|
|
MarkerLayer(
|
|
|
|
|
markers: _buildHopMarkers(
|
|
|
|
|
hops,
|
|
|
|
|
showLabels: _showNodeLabels,
|
|
|
|
|
),
|
|
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
],
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
if (observedPaths.length > 1)
|
2026-02-04 08:32:35 -08:00
|
|
|
_buildPathSelector(context, observedPaths, selectedIndex, (
|
|
|
|
|
index,
|
|
|
|
|
) {
|
|
|
|
|
setState(() {
|
|
|
|
|
_selectedPath = observedPaths[index].pathBytes;
|
2026-03-17 23:22:23 +01:00
|
|
|
_focusedHopIndex = null;
|
2026-02-04 08:32:35 -08:00
|
|
|
});
|
|
|
|
|
}),
|
2025-12-29 20:01:16 -07:00
|
|
|
if (points.isEmpty)
|
|
|
|
|
Center(
|
|
|
|
|
child: Card(
|
|
|
|
|
color: Colors.white.withValues(alpha: 0.9),
|
2026-01-11 17:13:50 -07:00
|
|
|
child: Padding(
|
2025-12-29 20:01:16 -07:00
|
|
|
padding: EdgeInsets.all(12),
|
2026-02-04 08:32:35 -08:00
|
|
|
child: Text(
|
|
|
|
|
context.l10n.channelPath_noRepeaterLocations,
|
|
|
|
|
),
|
2025-12-29 20:01:16 -07:00
|
|
|
),
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
_buildLegendCard(context, hops, isImperial),
|
2025-12-29 20:01:16 -07:00
|
|
|
],
|
|
|
|
|
),
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
Widget _buildPathSelector(
|
|
|
|
|
BuildContext context,
|
|
|
|
|
List<_ObservedPath> paths,
|
|
|
|
|
int selectedIndex,
|
|
|
|
|
ValueChanged<int> onSelected,
|
|
|
|
|
) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final l10n = context.l10n;
|
2025-12-27 15:32:32 -07:00
|
|
|
final selectedPath = paths[selectedIndex];
|
|
|
|
|
final label = selectedPath.isPrimary
|
2026-01-11 17:13:50 -07:00
|
|
|
? l10n.channelPath_primaryPath(selectedIndex + 1)
|
|
|
|
|
: l10n.channelPath_pathLabel(selectedIndex + 1);
|
2025-12-27 15:32:32 -07:00
|
|
|
return Positioned(
|
|
|
|
|
left: 16,
|
|
|
|
|
right: 16,
|
|
|
|
|
top: 16,
|
|
|
|
|
child: SafeArea(
|
|
|
|
|
child: Card(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
2026-01-11 17:13:50 -07:00
|
|
|
Text(
|
|
|
|
|
l10n.channelPath_observedPathHeader,
|
|
|
|
|
style: const TextStyle(fontWeight: FontWeight.w600),
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
|
DropdownButtonHideUnderline(
|
|
|
|
|
child: DropdownButton<int>(
|
|
|
|
|
isExpanded: true,
|
|
|
|
|
value: selectedIndex,
|
|
|
|
|
items: [
|
|
|
|
|
for (int i = 0; i < paths.length; i++)
|
|
|
|
|
DropdownMenuItem(
|
|
|
|
|
value: i,
|
|
|
|
|
child: Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
'${paths[i].isPrimary ? l10n.channelPath_primaryPath(i + 1) : l10n.channelPath_pathLabel(i + 1)}'
|
|
|
|
|
' • ${_formatHopCount(paths[i].pathBytes.length, l10n)}',
|
2025-12-27 15:32:32 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
onChanged: (value) {
|
|
|
|
|
if (value == null) return;
|
|
|
|
|
onSelected(value);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
|
Text(
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n.channelPath_selectedPathLabel(
|
|
|
|
|
label,
|
|
|
|
|
_formatPathPrefixes(selectedPath.pathBytes),
|
|
|
|
|
),
|
2025-12-27 15:32:32 -07:00
|
|
|
style: TextStyle(color: Colors.grey[700], fontSize: 12),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-21 01:08:23 -05:00
|
|
|
List<Marker> _buildHopMarkers(
|
|
|
|
|
List<_PathHop> hops, {
|
|
|
|
|
required bool showLabels,
|
|
|
|
|
}) {
|
|
|
|
|
final markers = <Marker>[];
|
|
|
|
|
for (final hop in hops) {
|
|
|
|
|
if (!hop.hasLocation) continue;
|
|
|
|
|
final point = hop.position!;
|
|
|
|
|
markers.add(
|
|
|
|
|
Marker(
|
|
|
|
|
point: point,
|
|
|
|
|
width: 35,
|
|
|
|
|
height: 35,
|
|
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.green,
|
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
|
|
|
boxShadow: [
|
|
|
|
|
BoxShadow(
|
|
|
|
|
color: Colors.black.withValues(alpha: 0.3),
|
|
|
|
|
blurRadius: 4,
|
|
|
|
|
offset: const Offset(0, 2),
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
child: Text(
|
|
|
|
|
hop.index.toString(),
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
fontSize: 12,
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
if (showLabels) {
|
|
|
|
|
markers.add(
|
|
|
|
|
_buildNodeLabelMarker(
|
|
|
|
|
point: point,
|
|
|
|
|
label: hop.contact?.name ?? _formatPrefix(hop.prefix),
|
2026-02-08 11:32:36 -08:00
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final selfLat = context.read<MeshCoreConnector>().selfLatitude;
|
|
|
|
|
final selfLon = context.read<MeshCoreConnector>().selfLongitude;
|
|
|
|
|
if (selfLat != null && selfLon != null) {
|
|
|
|
|
final selfPoint = LatLng(selfLat, selfLon);
|
|
|
|
|
markers.add(
|
|
|
|
|
Marker(
|
|
|
|
|
point: selfPoint,
|
2026-02-08 18:40:58 -08:00
|
|
|
width: 35,
|
|
|
|
|
height: 35,
|
|
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.teal,
|
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
|
|
|
boxShadow: [
|
|
|
|
|
BoxShadow(
|
|
|
|
|
color: Colors.black.withValues(alpha: 0.3),
|
|
|
|
|
blurRadius: 4,
|
|
|
|
|
offset: const Offset(0, 2),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
child: Text(
|
|
|
|
|
context.l10n.pathTrace_you,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
),
|
2026-02-08 11:32:36 -08:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-02-21 01:08:23 -05:00
|
|
|
);
|
|
|
|
|
if (showLabels) {
|
|
|
|
|
markers.add(
|
|
|
|
|
_buildNodeLabelMarker(
|
|
|
|
|
point: selfPoint,
|
|
|
|
|
label: context.l10n.pathTrace_you,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return markers;
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 01:08:23 -05:00
|
|
|
Marker _buildNodeLabelMarker({required LatLng point, required String label}) {
|
|
|
|
|
return Marker(
|
|
|
|
|
point: point,
|
|
|
|
|
width: 120,
|
|
|
|
|
height: 24,
|
|
|
|
|
alignment: Alignment.topCenter,
|
|
|
|
|
child: IgnorePointer(
|
|
|
|
|
child: Transform.translate(
|
2026-02-21 14:55:42 -08:00
|
|
|
offset: const Offset(0, -20),
|
|
|
|
|
child: FittedBox(
|
|
|
|
|
fit: BoxFit.contain,
|
|
|
|
|
child: Container(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.black54,
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
),
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
child: Text(
|
|
|
|
|
label,
|
|
|
|
|
maxLines: 1,
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
fontSize: 11,
|
|
|
|
|
fontWeight: FontWeight.w500,
|
2026-02-21 01:08:23 -05:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildLegendCard(
|
|
|
|
|
BuildContext context,
|
|
|
|
|
List<_PathHop> hops,
|
|
|
|
|
bool isImperial,
|
|
|
|
|
) {
|
2026-01-11 17:13:50 -07:00
|
|
|
final l10n = context.l10n;
|
2025-12-26 13:33:03 -07:00
|
|
|
final maxHeight = MediaQuery.of(context).size.height * 0.35;
|
|
|
|
|
final estimatedHeight = 72.0 + (hops.length * 56.0);
|
|
|
|
|
final cardHeight = max(96.0, min(maxHeight, estimatedHeight));
|
|
|
|
|
|
|
|
|
|
return Positioned(
|
|
|
|
|
left: 16,
|
|
|
|
|
right: 16,
|
|
|
|
|
bottom: 16,
|
|
|
|
|
child: SizedBox(
|
|
|
|
|
height: cardHeight,
|
|
|
|
|
child: Card(
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
2026-01-11 17:13:50 -07:00
|
|
|
Padding(
|
|
|
|
|
padding: const EdgeInsets.all(12),
|
2025-12-26 13:33:03 -07:00
|
|
|
child: Text(
|
2026-02-21 01:08:23 -05:00
|
|
|
'${l10n.channelPath_repeaterHops} ${formatDistance(_pathDistance, isImperial: isImperial)}',
|
2026-01-11 17:13:50 -07:00
|
|
|
style: const TextStyle(fontWeight: FontWeight.w600),
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const Divider(height: 1),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: hops.isEmpty
|
2026-01-11 17:13:50 -07:00
|
|
|
? Center(
|
|
|
|
|
child: Text(l10n.channelPath_noHopDetailsAvailable),
|
2025-12-26 13:33:03 -07:00
|
|
|
)
|
|
|
|
|
: ListView.separated(
|
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
|
|
|
itemCount: hops.length,
|
2026-02-14 02:22:45 -07:00
|
|
|
separatorBuilder: (_, _) => const Divider(height: 1),
|
2025-12-26 13:33:03 -07:00
|
|
|
itemBuilder: (context, index) {
|
|
|
|
|
final hop = hops[index];
|
2026-03-17 23:22:23 +01:00
|
|
|
final isFocused = _focusedHopIndex == hop.index;
|
2025-12-26 13:33:03 -07:00
|
|
|
return ListTile(
|
|
|
|
|
dense: true,
|
2026-03-17 23:22:23 +01:00
|
|
|
enabled: hop.hasLocation,
|
|
|
|
|
selected: isFocused,
|
|
|
|
|
selectedTileColor: Theme.of(
|
|
|
|
|
context,
|
|
|
|
|
).colorScheme.primary.withValues(alpha: 0.12),
|
|
|
|
|
onTap: hop.hasLocation
|
|
|
|
|
? () => _onHopTapped(hop)
|
|
|
|
|
: null,
|
2025-12-26 13:33:03 -07:00
|
|
|
leading: CircleAvatar(
|
|
|
|
|
radius: 14,
|
|
|
|
|
child: Text(
|
|
|
|
|
hop.index.toString(),
|
|
|
|
|
style: const TextStyle(fontSize: 12),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
title: Text(hop.displayLabel),
|
|
|
|
|
subtitle: Text(
|
|
|
|
|
hop.hasLocation
|
|
|
|
|
? '${hop.position!.latitude.toStringAsFixed(5)}, '
|
2026-02-04 08:32:35 -08:00
|
|
|
'${hop.position!.longitude.toStringAsFixed(5)}'
|
2026-01-11 17:13:50 -07:00
|
|
|
: l10n.channelPath_noLocationData,
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _PathHop {
|
|
|
|
|
final int index;
|
|
|
|
|
final int prefix;
|
|
|
|
|
final Contact? contact;
|
|
|
|
|
final LatLng? position;
|
2026-01-11 17:13:50 -07:00
|
|
|
final AppLocalizations l10n;
|
2025-12-26 13:33:03 -07:00
|
|
|
|
|
|
|
|
const _PathHop({
|
|
|
|
|
required this.index,
|
|
|
|
|
required this.prefix,
|
|
|
|
|
required this.contact,
|
|
|
|
|
required this.position,
|
2026-01-11 17:13:50 -07:00
|
|
|
required this.l10n,
|
2025-12-26 13:33:03 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
bool get hasLocation => position != null;
|
|
|
|
|
|
|
|
|
|
String get displayLabel {
|
|
|
|
|
final prefixLabel = _formatPrefix(prefix);
|
2026-01-11 17:13:50 -07:00
|
|
|
return '($prefixLabel) ${_resolveName(contact, l10n)}';
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
class _ObservedPath {
|
|
|
|
|
final Uint8List pathBytes;
|
|
|
|
|
final bool isPrimary;
|
|
|
|
|
|
2026-02-04 08:32:35 -08:00
|
|
|
const _ObservedPath({required this.pathBytes, required this.isPrimary});
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
List<_PathHop> _buildPathHops(
|
|
|
|
|
Uint8List pathBytes,
|
2026-03-17 21:56:42 +01:00
|
|
|
MeshCoreConnector connector,
|
2026-01-11 17:13:50 -07:00
|
|
|
AppLocalizations l10n,
|
|
|
|
|
) {
|
2026-03-17 21:56:42 +01:00
|
|
|
if (pathBytes.isEmpty) return const [];
|
|
|
|
|
final candidatesByPrefix = <int, List<Contact>>{};
|
2026-03-26 16:46:01 -07:00
|
|
|
final allContacts = connector.allContacts;
|
|
|
|
|
for (final contact in allContacts) {
|
2026-03-17 21:56:42 +01:00
|
|
|
if (contact.publicKey.isEmpty) continue;
|
|
|
|
|
if (contact.type != advTypeRepeater && contact.type != advTypeRoom) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
final prefix = contact.publicKey.first;
|
|
|
|
|
candidatesByPrefix.putIfAbsent(prefix, () => <Contact>[]).add(contact);
|
|
|
|
|
}
|
|
|
|
|
for (final candidates in candidatesByPrefix.values) {
|
|
|
|
|
candidates.sort((a, b) => b.lastSeen.compareTo(a.lastSeen));
|
|
|
|
|
}
|
|
|
|
|
final startPoint =
|
|
|
|
|
(connector.selfLatitude != null && connector.selfLongitude != null)
|
|
|
|
|
? LatLng(connector.selfLatitude!, connector.selfLongitude!)
|
|
|
|
|
: null;
|
|
|
|
|
var previousPosition = startPoint;
|
|
|
|
|
final distance = Distance();
|
2026-03-26 21:37:50 -07:00
|
|
|
var lastDistance = 0.0;
|
|
|
|
|
var bestDistance = 0.0;
|
2025-12-26 13:33:03 -07:00
|
|
|
final hops = <_PathHop>[];
|
|
|
|
|
for (var i = 0; i < pathBytes.length; i++) {
|
2026-03-17 21:56:42 +01:00
|
|
|
final searchPoint = i == 0 ? startPoint : previousPosition;
|
|
|
|
|
final candidates = candidatesByPrefix[pathBytes[i]];
|
|
|
|
|
Contact? contact;
|
|
|
|
|
if (candidates != null && candidates.isNotEmpty) {
|
|
|
|
|
var bestIndex = 0;
|
|
|
|
|
if (searchPoint != null) {
|
2026-03-26 21:37:50 -07:00
|
|
|
bestDistance = double.infinity;
|
2026-03-17 21:56:42 +01:00
|
|
|
for (var j = 0; j < candidates.length; j++) {
|
|
|
|
|
final candidate = candidates[j];
|
2026-03-18 07:00:16 +01:00
|
|
|
if (!candidate.hasLocation ||
|
|
|
|
|
candidate.latitude == null ||
|
|
|
|
|
candidate.longitude == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-03-17 21:56:42 +01:00
|
|
|
final currentDistance = distance(
|
|
|
|
|
searchPoint,
|
|
|
|
|
LatLng(candidate.latitude!, candidate.longitude!),
|
|
|
|
|
);
|
|
|
|
|
if (currentDistance < bestDistance) {
|
|
|
|
|
bestDistance = currentDistance;
|
|
|
|
|
bestIndex = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
contact = candidates.removeAt(bestIndex);
|
|
|
|
|
if (candidates.isEmpty) {
|
|
|
|
|
candidatesByPrefix.remove(pathBytes[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-17 22:23:23 +01:00
|
|
|
final resolvedPosition = _resolvePosition(contact);
|
|
|
|
|
if (resolvedPosition != null) {
|
|
|
|
|
previousPosition = resolvedPosition;
|
|
|
|
|
}
|
2026-03-26 21:37:50 -07:00
|
|
|
// If the best candidate is much farther than the previous hop, it's likely not the correct match.
|
|
|
|
|
if (lastDistance + bestDistance > 70000 &&
|
|
|
|
|
candidates != null &&
|
|
|
|
|
candidates.isNotEmpty) {
|
|
|
|
|
i--;
|
|
|
|
|
lastDistance = bestDistance;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
lastDistance = bestDistance;
|
|
|
|
|
|
2025-12-26 13:33:03 -07:00
|
|
|
hops.add(
|
|
|
|
|
_PathHop(
|
|
|
|
|
index: i + 1,
|
2026-03-17 21:56:42 +01:00
|
|
|
prefix: pathBytes[i],
|
2025-12-26 13:33:03 -07:00
|
|
|
contact: contact,
|
2026-03-17 22:23:23 +01:00
|
|
|
position: resolvedPosition,
|
2026-01-11 17:13:50 -07:00
|
|
|
l10n: l10n,
|
2025-12-26 13:33:03 -07:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return hops;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LatLng? _resolvePosition(Contact? contact) {
|
|
|
|
|
if (contact == null) return null;
|
2026-03-17 21:56:42 +01:00
|
|
|
if (!contact.hasLocation) return null;
|
2026-03-18 08:06:22 +01:00
|
|
|
final latitude = contact.latitude;
|
|
|
|
|
final longitude = contact.longitude;
|
|
|
|
|
if (latitude == null || longitude == null) return null;
|
|
|
|
|
return LatLng(latitude, longitude);
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String _formatPrefix(int prefix) {
|
|
|
|
|
return prefix.toRadixString(16).padLeft(2, '0').toUpperCase();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 15:32:32 -07:00
|
|
|
String _formatPathPrefixes(Uint8List pathBytes) {
|
|
|
|
|
return pathBytes
|
|
|
|
|
.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase())
|
|
|
|
|
.join(',');
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
String _formatHopCount(int count, AppLocalizations l10n) {
|
|
|
|
|
return l10n.chat_hopsCount(count);
|
2025-12-27 15:32:32 -07:00
|
|
|
}
|
|
|
|
|
|
2026-01-11 17:13:50 -07:00
|
|
|
String _resolveName(Contact? contact, AppLocalizations l10n) {
|
|
|
|
|
if (contact == null) return l10n.channelPath_unknownRepeater;
|
2025-12-26 13:33:03 -07:00
|
|
|
final name = contact.name.trim();
|
|
|
|
|
if (name.isEmpty || name.toLowerCase() == 'unknown') {
|
2026-01-11 17:13:50 -07:00
|
|
|
return l10n.channelPath_unknownRepeater;
|
2025-12-26 13:33:03 -07:00
|
|
|
}
|
|
|
|
|
return name;
|
|
|
|
|
}
|
2025-12-27 15:32:32 -07:00
|
|
|
|
|
|
|
|
Uint8List _selectPrimaryPath(Uint8List pathBytes, List<Uint8List> variants) {
|
|
|
|
|
Uint8List primary = pathBytes;
|
|
|
|
|
for (final variant in variants) {
|
|
|
|
|
if (variant.length > primary.length) {
|
|
|
|
|
primary = variant;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return primary;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Uint8List> _otherPaths(Uint8List primary, List<Uint8List> variants) {
|
|
|
|
|
final others = <Uint8List>[];
|
|
|
|
|
for (final variant in variants) {
|
|
|
|
|
if (variant.isEmpty) continue;
|
|
|
|
|
if (!_pathsEqual(primary, variant)) {
|
|
|
|
|
others.add(variant);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return others;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<_ObservedPath> _buildObservedPaths(
|
|
|
|
|
Uint8List primary,
|
|
|
|
|
List<Uint8List> variants,
|
|
|
|
|
) {
|
|
|
|
|
final observed = <_ObservedPath>[];
|
|
|
|
|
|
|
|
|
|
void addPath(Uint8List pathBytes, bool isPrimary) {
|
|
|
|
|
if (pathBytes.isEmpty) return;
|
|
|
|
|
for (final existing in observed) {
|
|
|
|
|
if (_pathsEqual(existing.pathBytes, pathBytes)) return;
|
|
|
|
|
}
|
|
|
|
|
observed.add(_ObservedPath(pathBytes: pathBytes, isPrimary: isPrimary));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addPath(primary, true);
|
|
|
|
|
for (final variant in variants) {
|
|
|
|
|
addPath(variant, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return observed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint8List _resolveSelectedPath(
|
|
|
|
|
Uint8List? selected,
|
|
|
|
|
List<_ObservedPath> observedPaths,
|
|
|
|
|
Uint8List fallback,
|
|
|
|
|
) {
|
|
|
|
|
if (selected != null) {
|
|
|
|
|
for (final path in observedPaths) {
|
|
|
|
|
if (_pathsEqual(path.pathBytes, selected)) {
|
|
|
|
|
return path.pathBytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (observedPaths.isNotEmpty) {
|
|
|
|
|
return observedPaths.first.pathBytes;
|
|
|
|
|
}
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int _indexForPath(Uint8List selected, List<_ObservedPath> paths) {
|
|
|
|
|
for (int i = 0; i < paths.length; i++) {
|
|
|
|
|
if (_pathsEqual(paths[i].pathBytes, selected)) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _pathsEqual(Uint8List a, Uint8List b) {
|
|
|
|
|
if (a.length != b.length) return false;
|
|
|
|
|
for (var i = 0; i < a.length; i++) {
|
|
|
|
|
if (a[i] != b[i]) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|