mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-06-14 22:55:12 +10:00
Refactor ranking calculation for direct repeaters and update path handling in channel message screens
This commit is contained in:
@@ -59,13 +59,12 @@ class DirectRepeater {
|
||||
return -1; // Stale repeaters get lowest rank
|
||||
}
|
||||
// Higher SNR gets higher rank and recency within maxAgeMinutes breaks ties.
|
||||
final snrOffset = snr + 31.75;
|
||||
final ageMs =
|
||||
DateTime.now().millisecondsSinceEpoch -
|
||||
lastUpdated.millisecondsSinceEpoch;
|
||||
final maxAgeMs = maxAgeMinutes * 60 * 1000;
|
||||
final recencyScore = (maxAgeMs - ageMs).clamp(0, maxAgeMs);
|
||||
return (snrOffset * 1000).round() + recencyScore;
|
||||
return (snr * snr).round() + recencyScore;
|
||||
}
|
||||
|
||||
bool isStale() {
|
||||
|
||||
@@ -901,7 +901,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChannelMessagePathScreen(message: message),
|
||||
builder: (context) =>
|
||||
ChannelMessagePathScreen(message: message, channelMessage: true),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,18 +17,27 @@ import '../models/contact.dart';
|
||||
|
||||
class ChannelMessagePathScreen extends StatelessWidget {
|
||||
final ChannelMessage message;
|
||||
|
||||
const ChannelMessagePathScreen({super.key, required this.message});
|
||||
final bool channelMessage;
|
||||
const ChannelMessagePathScreen({
|
||||
super.key,
|
||||
required this.message,
|
||||
this.channelMessage = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<MeshCoreConnector>(
|
||||
builder: (context, connector, _) {
|
||||
final l10n = context.l10n;
|
||||
final primaryPath = _selectPrimaryPath(
|
||||
final primaryPathTmp = _selectPrimaryPath(
|
||||
message.pathBytes,
|
||||
message.pathVariants,
|
||||
);
|
||||
|
||||
final primaryPath = !channelMessage && !message.isOutgoing
|
||||
? Uint8List.fromList(primaryPathTmp.reversed.toList())
|
||||
: primaryPathTmp;
|
||||
|
||||
final hops = _buildPathHops(primaryPath, connector.contacts, l10n);
|
||||
final hasHopDetails = primaryPath.isNotEmpty;
|
||||
final observedLabel = _formatObservedHops(
|
||||
@@ -37,7 +46,6 @@ class ChannelMessagePathScreen extends StatelessWidget {
|
||||
l10n,
|
||||
);
|
||||
final extraPaths = _otherPaths(primaryPath, message.pathVariants);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(l10n.channelPath_title),
|
||||
@@ -50,9 +58,9 @@ class ChannelMessagePathScreen extends StatelessWidget {
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PathTraceMapScreen(
|
||||
title: context.l10n.contacts_repeaterPathTrace,
|
||||
path: Uint8List.fromList(primaryPath),
|
||||
path: primaryPath,
|
||||
flipPathRound: true,
|
||||
reversePathRound: true,
|
||||
reversePathRound: !message.isOutgoing,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -62,7 +70,7 @@ class ChannelMessagePathScreen extends StatelessWidget {
|
||||
tooltip: l10n.channelPath_viewMap,
|
||||
onPressed: hasHopDetails
|
||||
? () {
|
||||
_openPathMap(context);
|
||||
_openPathMap(context, channelMessage: channelMessage);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
@@ -248,13 +256,18 @@ class ChannelMessagePathScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _openPathMap(BuildContext context, {Uint8List? initialPath}) {
|
||||
void _openPathMap(
|
||||
BuildContext context, {
|
||||
Uint8List? initialPath,
|
||||
bool channelMessage = false,
|
||||
}) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChannelMessagePathMapScreen(
|
||||
message: message,
|
||||
initialPath: initialPath,
|
||||
channelMessage: channelMessage,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -264,11 +277,13 @@ class ChannelMessagePathScreen extends StatelessWidget {
|
||||
class ChannelMessagePathMapScreen extends StatefulWidget {
|
||||
final ChannelMessage message;
|
||||
final Uint8List? initialPath;
|
||||
final bool channelMessage;
|
||||
|
||||
const ChannelMessagePathMapScreen({
|
||||
super.key,
|
||||
required this.message,
|
||||
this.initialPath,
|
||||
this.channelMessage = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -323,11 +338,16 @@ class _ChannelMessagePathMapScreenState
|
||||
primaryPath,
|
||||
widget.message.pathVariants,
|
||||
);
|
||||
final selectedPath = _resolveSelectedPath(
|
||||
final selectedPathTmp = _resolveSelectedPath(
|
||||
_selectedPath,
|
||||
observedPaths,
|
||||
primaryPath,
|
||||
);
|
||||
|
||||
final selectedPath = !widget.channelMessage && widget.message.isOutgoing
|
||||
? Uint8List.fromList(selectedPathTmp.reversed.toList())
|
||||
: selectedPathTmp;
|
||||
|
||||
final selectedIndex = _indexForPath(selectedPath, observedPaths);
|
||||
final hops = _buildPathHops(
|
||||
selectedPath,
|
||||
|
||||
@@ -105,7 +105,7 @@ class _MapScreenState extends State<MapScreen> {
|
||||
double _zoomFromStdDev(double latStdDev, double lonStdDev) {
|
||||
final maxSpread = max(latStdDev, lonStdDev);
|
||||
if (maxSpread <= 0) return 13.0;
|
||||
// Approzimate: each zoom level halves the visible area
|
||||
// Approximate: each zoom level halves the visible area
|
||||
// ~0.01 degrees spread -> zoom 13, ~0.1 -> zoom 10, ~1.0 -> zoom 7
|
||||
final zoom = 10.0 - log(maxSpread * 10 + 1) / ln10 * 3;
|
||||
return zoom.clamp(4.0, 15.0);
|
||||
@@ -825,7 +825,7 @@ class _MapScreenState extends State<MapScreen> {
|
||||
color: _getNodeColor(contact.type),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(contact.name)),
|
||||
Expanded(child: SelectableText(contact.name)),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
@@ -996,7 +996,7 @@ class _MapScreenState extends State<MapScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(value, style: const TextStyle(fontSize: 14)),
|
||||
SelectableText(value, style: const TextStyle(fontSize: 14)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -46,6 +46,7 @@ class PathTraceData {
|
||||
class PathTraceMapScreen extends StatefulWidget {
|
||||
final String title;
|
||||
final Uint8List path;
|
||||
final int? repeaterId;
|
||||
final bool flipPathRound;
|
||||
final bool reversePathRound;
|
||||
|
||||
@@ -53,6 +54,7 @@ class PathTraceMapScreen extends StatefulWidget {
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.path,
|
||||
this.repeaterId,
|
||||
this.flipPathRound = false,
|
||||
this.reversePathRound = false,
|
||||
});
|
||||
@@ -97,7 +99,7 @@ class _PathTraceMapScreenState extends State<PathTraceMapScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Uint8List addReturnpath(Uint8List pathBytes) {
|
||||
Uint8List addReturnPath(Uint8List pathBytes) {
|
||||
Uint8List? traceBytes;
|
||||
final len = (pathBytes.length + pathBytes.length - 1);
|
||||
traceBytes = Uint8List(len);
|
||||
@@ -125,11 +127,13 @@ class _PathTraceMapScreenState extends State<PathTraceMapScreen> {
|
||||
: widget.path;
|
||||
|
||||
if (widget.flipPathRound) {
|
||||
path = addReturnpath(pathTmp);
|
||||
path = addReturnPath(pathTmp);
|
||||
} else {
|
||||
path = pathTmp;
|
||||
}
|
||||
|
||||
print('Initiating path trace with path: ${_formatPathPrefixes(path)}');
|
||||
|
||||
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
|
||||
final frame = buildTraceReq(
|
||||
DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
|
||||
Reference in New Issue
Block a user