Merge pull request #1 from ericszimmermann/ez_snr_multibyte2

Multibyte Support for SNR-Indicator, channel message_bubble and Setting
This commit is contained in:
PacoX
2026-05-19 10:14:03 +02:00
committed by GitHub
47 changed files with 438 additions and 119 deletions
+192 -19
View File
@@ -49,18 +49,53 @@ import 'meshcore_protocol.dart';
class DirectRepeater {
static const int maxAgeMinutes = 30; // Max age for direct repeater info
final int pubkeyFirstByte;
List<int> pubkeyPrefix;
int pathHashWidth;
String? contactKeyHex;
double snr;
DateTime lastUpdated;
DirectRepeater({
required this.pubkeyFirstByte,
required List<int> pubkeyPrefix,
required this.pathHashWidth,
this.contactKeyHex,
required this.snr,
DateTime? lastUpdated,
}) : lastUpdated = lastUpdated ?? DateTime.now();
}) : pubkeyPrefix = List.unmodifiable(pubkeyPrefix),
lastUpdated = lastUpdated ?? DateTime.now();
void update(double newSNR) {
String get pubkeyPrefixHex => pubkeyPrefix
.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase())
.join();
bool matchesPrefix(List<int> prefix) {
return pubkeyPrefix.length == prefix.length &&
listEquals(pubkeyPrefix, prefix);
}
bool matchesPathStart(List<int> pathBytes, int pathHashByteWidth) {
final width = pathHashByteWidth.clamp(1, 4).toInt();
if (pathBytes.length < width || pubkeyPrefix.length != width) {
return false;
}
return listEquals(pubkeyPrefix, pathBytes.sublist(0, width));
}
void update(
double newSNR, {
List<int>? pubkeyPrefix,
int? pathHashWidth,
String? contactKeyHex,
}) {
snr = newSNR;
if (pubkeyPrefix != null &&
pubkeyPrefix.length >= this.pubkeyPrefix.length) {
this.pubkeyPrefix = List.unmodifiable(pubkeyPrefix);
}
if (pathHashWidth != null && pathHashWidth >= this.pathHashWidth) {
this.pathHashWidth = pathHashWidth;
}
this.contactKeyHex ??= contactKeyHex;
lastUpdated = DateTime.now();
}
@@ -2553,7 +2588,14 @@ class MeshCoreConnector extends ChangeNotifier {
Future<void> setPathHashMode(int mode) async {
if (!isConnected) return;
await sendFrame(buildSetPathHashModeFrame(mode.clamp(0, 2)));
final clampedMode = mode.clamp(0, 2).toInt();
await sendFrame(buildSetPathHashModeFrame(clampedMode));
final nextWidth = clampedMode + 1;
if (_pathHashByteWidth != nextWidth) {
_pathHashByteWidth = nextWidth;
_directRepeaters.clear();
notifyListeners();
}
}
Future<void> refreshDeviceInfo() async {
@@ -3853,12 +3895,16 @@ class MeshCoreConnector extends ChangeNotifier {
_clientRepeat = frame[80] != 0;
}
// Path hash mode v10+ (byte 81): width = mode + 1 byte(s) per hop
final previousPathHashByteWidth = _pathHashByteWidth;
if (frame.length >= 82) {
final mode = (frame[81] & 0xFF).clamp(0, 3);
_pathHashByteWidth = mode + 1;
} else {
_pathHashByteWidth = 1;
}
if (_pathHashByteWidth != previousPathHashByteWidth) {
_directRepeaters.clear();
}
// Firmware reports MAX_CONTACTS / 2 for v3+ device info.
final reportedContacts = frame[2];
@@ -4298,7 +4344,11 @@ class MeshCoreConnector extends ChangeNotifier {
for (var i = 0; i < _contacts.length; i++) {
final contact = _contacts[i];
if (contact.type != advTypeChat) continue;
if (_pathMatchesContact(pathBytes, contact.publicKey, pathHashWidth: pathHashWidth)) {
if (_pathMatchesContact(
pathBytes,
contact.publicKey,
pathHashWidth: pathHashWidth,
)) {
matches.add(i);
}
}
@@ -4315,7 +4365,11 @@ class MeshCoreConnector extends ChangeNotifier {
}
}
bool _pathMatchesContact(Uint8List pathBytes, Uint8List publicKey, {int? pathHashWidth}) {
bool _pathMatchesContact(
Uint8List pathBytes,
Uint8List publicKey, {
int? pathHashWidth,
}) {
final w = pathHashWidth ?? _pathHashByteWidth;
if (pathBytes.isEmpty || publicKey.length < w) return false;
for (int i = 0; i + w <= pathBytes.length; i += w) {
@@ -5529,6 +5583,7 @@ class MeshCoreConnector extends ChangeNotifier {
repeats: message.repeats,
repeatCount: message.repeatCount,
pathLength: message.pathLength,
pathHashWidth: message.pathHashWidth,
pathBytes: message.pathBytes,
pathVariants: message.pathVariants,
channelIndex: message.channelIndex,
@@ -5565,6 +5620,7 @@ class MeshCoreConnector extends ChangeNotifier {
messages[existingIndex] = existing.copyWith(
repeatCount: newRepeatCount,
pathLength: mergedPathLength,
pathHashWidth: existing.pathHashWidth ?? processedMessage.pathHashWidth,
pathBytes: mergedPathBytes,
pathVariants: mergedPathVariants,
packetHash: existing.packetHash ?? processedMessage.packetHash,
@@ -5929,6 +5985,7 @@ class MeshCoreConnector extends ChangeNotifier {
//final payloadVer = (header >> 6) & 0x03;
final pathLenRaw = packet.readByte();
final pathByteLen = _decodePathByteLen(pathLenRaw);
final pathHashWidth = _decodePathHashWidth(pathLenRaw);
final pathBytes = packet.readBytes(pathByteLen);
final payload = packet.readBytes(packet.remaining);
@@ -5939,6 +5996,7 @@ class MeshCoreConnector extends ChangeNotifier {
rawPacket,
payload,
pathBytes,
pathHashWidth,
routeType,
snr,
);
@@ -6042,6 +6100,7 @@ class MeshCoreConnector extends ChangeNotifier {
Uint8List rawPacket,
Uint8List payload,
Uint8List path,
int pathHashWidth,
int routeType,
double snr,
) {
@@ -6122,7 +6181,12 @@ class MeshCoreConnector extends ChangeNotifier {
} else {
_handleDiscovery(newContact, rawPacket);
}
_updateDirectRepeater(newContact, snr, path);
_updateDirectRepeater(
newContact,
snr,
path,
pathHashWidth: pathHashWidth,
);
return;
}
@@ -6160,7 +6224,12 @@ class MeshCoreConnector extends ChangeNotifier {
_pathHistoryService!.handlePathUpdated(_contacts[existingIndex]);
}
_updateDirectRepeater(_contacts[existingIndex], snr, path);
_updateDirectRepeater(
_contacts[existingIndex],
snr,
path,
pathHashWidth: pathHashWidth,
);
appLogger.info(
'After merge: pathOverride=${_contacts[existingIndex].pathOverride}, devicePath=${_contacts[existingIndex].pathLength}',
@@ -6169,10 +6238,41 @@ class MeshCoreConnector extends ChangeNotifier {
}
}
void _updateDirectRepeater(Contact contact, double snr, Uint8List path) {
final pubkeyFirstByte = path.isNotEmpty
? path.last
: contact.publicKey.first;
void _updateDirectRepeater(
Contact contact,
double snr,
Uint8List path, {
required int pathHashWidth,
}) {
final hashWidth = pathHashWidth.clamp(1, 4).toInt();
if (path.isNotEmpty && path.length < hashWidth) {
return;
}
final pubkeyPrefix = path.isNotEmpty
? path.sublist(math.max(0, path.length - hashWidth))
: contact.publicKey.sublist(
0,
math.min(hashWidth, contact.publicKey.length),
);
final contactKeyHex = _resolveDirectRepeaterContactKeyHex(
contact,
pubkeyPrefix,
path.isEmpty,
);
final knownRepeaters = contactKeyHex == null
? _directRepeaters
.where(
(r) =>
r.contactKeyHex != null &&
_contactKeyMatchesPrefix(r.contactKeyHex!, pubkeyPrefix),
)
.toList()
: const <DirectRepeater>[];
final knownRepeater = knownRepeaters.length == 1
? knownRepeaters.first
: null;
final effectiveContactKeyHex =
contactKeyHex ?? knownRepeater?.contactKeyHex;
_directRepeaters.removeWhere((r) => r.isStale());
@@ -6183,9 +6283,25 @@ class MeshCoreConnector extends ChangeNotifier {
return;
}
final isTracked = _directRepeaters.where(
(r) => r.pubkeyFirstByte == pubkeyFirstByte,
);
final isTracked = _directRepeaters.where((r) {
if (knownRepeater != null) {
return identical(r, knownRepeater);
}
if (effectiveContactKeyHex != null) {
return r.contactKeyHex == effectiveContactKeyHex ||
(r.contactKeyHex == null &&
_contactKeyMatchesPrefix(
effectiveContactKeyHex,
r.pubkeyPrefix,
));
}
if (r.contactKeyHex == null &&
r.pathHashWidth == hashWidth &&
r.matchesPrefix(pubkeyPrefix)) {
return true;
}
return false;
}).toList();
final sortedRepeaters = List<DirectRepeater>.from(_directRepeaters)
..sort((a, b) => b.snr.compareTo(a.snr));
@@ -6201,15 +6317,68 @@ class MeshCoreConnector extends ChangeNotifier {
if (isTracked.isNotEmpty) {
final repeater = isTracked.first;
repeater.update(snr);
repeater.update(
snr,
pubkeyPrefix: pubkeyPrefix,
pathHashWidth: hashWidth,
contactKeyHex: effectiveContactKeyHex,
);
if (effectiveContactKeyHex != null) {
_directRepeaters.removeWhere(
(r) =>
!identical(r, repeater) &&
(r.contactKeyHex == effectiveContactKeyHex ||
(r.contactKeyHex == null &&
_contactKeyMatchesPrefix(
effectiveContactKeyHex,
r.pubkeyPrefix,
))),
);
}
} else if (_directRepeaters.length < 5) {
_directRepeaters.add(
DirectRepeater(pubkeyFirstByte: pubkeyFirstByte, snr: snr),
DirectRepeater(
pubkeyPrefix: pubkeyPrefix,
pathHashWidth: hashWidth,
contactKeyHex: effectiveContactKeyHex,
snr: snr,
),
);
}
notifyListeners();
}
String? _resolveDirectRepeaterContactKeyHex(
Contact contact,
List<int> pubkeyPrefix,
bool pathIsEmpty,
) {
if (pathIsEmpty &&
(contact.type == advTypeRepeater || contact.type == advTypeRoom)) {
return contact.publicKeyHex;
}
final prefixMatches = allContacts
.where(
(c) =>
(c.type == advTypeRepeater || c.type == advTypeRoom) &&
_contactKeyMatchesPrefix(c.publicKeyHex, pubkeyPrefix),
)
.toList();
if (prefixMatches.length == 1) {
return prefixMatches.first.publicKeyHex;
}
return null;
}
bool _contactKeyMatchesPrefix(String contactKeyHex, List<int> pubkeyPrefix) {
final prefixHex = pubkeyPrefix
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join();
return contactKeyHex.startsWith(prefixHex);
}
void _handleAutoAddConfig(Uint8List frame) {
final reader = BufferReader(frame);
try {
@@ -6335,10 +6504,14 @@ const int _cipherMacSize = 2;
/// Bits 0-5: hash count (0-63), Bits 6-7: hash size code (0=1byte, 1=2bytes, 2=3bytes).
int _decodePathByteLen(int pathLenRaw) {
final hashCount = pathLenRaw & 63;
final hashSize = ((pathLenRaw >> 6) & 0x03) + 1;
final hashSize = _decodePathHashWidth(pathLenRaw);
return hashCount * hashSize;
}
int _decodePathHashWidth(int pathLenRaw) {
return ((pathLenRaw >> 6) & 0x03) + 1;
}
class _RawPacket {
final int header;
final int routeType;
+12 -14
View File
@@ -15,7 +15,10 @@ class PathHelper {
.join();
}
static List<Uint8List> splitPathBytes(List<int> pathBytes, int hashByteWidth) {
static List<Uint8List> splitPathBytes(
List<int> pathBytes,
int hashByteWidth,
) {
if (pathBytes.isEmpty) return const [];
final width = hashByteWidth.clamp(1, 4);
@@ -50,18 +53,13 @@ class PathHelper {
final hex = formatHopHex(hopBytes);
// Find matching contacts by comparing public key prefix
final matches = allContacts
.where((c) {
if (c.publicKey.length < hopBytes.length) return false;
if (c.type != advTypeRepeater && c.type != advTypeRoom) return false;
// Compare bytes using listEquals for multi-byte support
return listEquals(
c.publicKey.sublist(0, hopBytes.length),
hopBytes,
);
})
.toList();
final matches = allContacts.where((c) {
if (c.publicKey.length < hopBytes.length) return false;
if (c.type != advTypeRepeater && c.type != advTypeRoom) return false;
// Compare bytes using listEquals for multi-byte support
return listEquals(c.publicKey.sublist(0, hopBytes.length), hopBytes);
}).toList();
if (matches.isEmpty) {
parts.add(hex);
} else if (matches.length == 1) {
@@ -70,7 +68,7 @@ class PathHelper {
parts.add(matches.map((c) => c.name).join(' | '));
}
}
return parts.join(' \u2192 ');
}
}
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Напреднал",
"repeater_advancedSettingsSubtitle": "Регулаторни копчета за опитни оператори",
"repeater_pathHashMode": "Режим за хеширане на пътища",
"repeater_pathHashModeHelper": "Байтовете, използвани за кодиране на идентификатора на този репитер в таговете за откриване на потоци/цикли, са: 0=1 байт (256 идентификатора, до 64 скача), 1=2 байта (65 000 идентификатора, до 32 скача), 2=3 байта (16 милиона идентификатора, до 21 скача). Версии 1.13 и по-стари версии на фърмуера използват многобайтови пътища – само след като мрежата е актуализирана до версия 1.14 или по-нова.",
"repeater_pathHashModeHelper": "Байтовете, използвани за кодиране на идентификатора на този репитер в таговете за flood път/откриване на цикли. 0=1 байт (256 идентификатора, до 64 скока), 1=2 байта (65 000 идентификатора, до 32 скока), 2=3 байта (16 милиона идентификатора, до 21 скока). Фърмуер преди v1.14 винаги използва 1-байтови пътища; v1.14 и по-нови версии могат да се конфигурират за 2- или 3-байтови пътища.",
"repeater_txDelay": "Забавяне на проекта \"Flood TX\"",
"repeater_txDelayHelper": "Предавайте разстоянието между пакетите за трафик при наводнения, като множител на времето за пренос на пакета (0-2, по подразбиране 0.5). По-висока стойност означава по-малко сблъсъци, но по-бавно предаване.",
"repeater_directTxDelay": "Директно забавяне на сигнала",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Fortgeschritten",
"repeater_advancedSettingsSubtitle": "Regler für erfahrene Bediener",
"repeater_pathHashMode": "Hash-Modus für Pfade",
"repeater_pathHashModeHelper": "Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware-Versionen 1.13 und älter verwenden mehrstellige Pfade ab Version 1.14+ wird nur ein Pfad erstellt, sobald das Netzwerk aktiv ist.",
"repeater_pathHashModeHelper": "Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware vor v1.14 verwendet immer 1-Byte-Pfade; ab v1.14 können 2- oder 3-Byte-Pfade eingestellt werden.",
"repeater_txDelay": "Verzögerung bei Flood TX",
"repeater_txDelayHelper": "Wiederholung des Abstands für Hochwasser-Verkehr, als Multiplikator der Übertragungszeit des Pakets (0-2, Standardwert 0,5). Höherer Wert = weniger Kollisionen, aber langsamere Übertragung.",
"repeater_directTxDelay": "Direkter TX-Verzögerung",
+1 -1
View File
@@ -1361,7 +1361,7 @@
"repeater_advancedSettings": "Advanced",
"repeater_advancedSettingsSubtitle": "Tuning knobs for experienced operators",
"repeater_pathHashMode": "Path hash mode",
"repeater_pathHashModeHelper": "Bytes used to encode this repeater's ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.",
"repeater_pathHashModeHelper": "Bytes used to encode this repeater's ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). Firmware before v1.14 always used 1-byte paths; v1.14 and newer can be configured for 2- or 3-byte paths.",
"repeater_txDelay": "Flood TX delay",
"repeater_txDelayHelper": "Retransmit spacing for flood traffic, as a multiplier of the packet's airtime (0-2, default 0.5). Higher = fewer collisions but slower delivery.",
"repeater_directTxDelay": "Direct TX delay",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Avanzado",
"repeater_advancedSettingsSubtitle": "Perillas de ajuste para operadores experimentados",
"repeater_pathHashMode": "Modo de hash de ruta",
"repeater_pathHashModeHelper": "Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). Las versiones 1.13 y anteriores de firmware eliminan rutas de múltiples bytes; solo se detectan una vez que la red está activa en la versión 1.14 o posterior.",
"repeater_pathHashModeHelper": "Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta flood/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). El firmware anterior a v1.14 siempre usaba rutas de 1 byte; v1.14 y posteriores pueden configurarse para rutas de 2 o 3 bytes.",
"repeater_txDelay": "Retraso en Flood, TX",
"repeater_txDelayHelper": "Ajuste de retransmisión para el tráfico de inundación, como un multiplicador del tiempo de transmisión del paquete (0-2, valor predeterminado 0.5). Un valor más alto significa menos colisiones, pero una entrega más lenta.",
"repeater_directTxDelay": "Retraso directo en TX",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Avancé",
"repeater_advancedSettingsSubtitle": "Molettes de réglage pour les opérateurs expérimentés",
"repeater_pathHashMode": "Mode de hachage de chemin",
"repeater_pathHashModeHelper": "Octets utilisés pour encoder l'ID de ce routeur dans les balises de détection de flux/boucles. 0 = 1 octet (256 ID, jusqu'à 64 sauts), 1 = 2 octets (65 000 ID, jusqu'à 32 sauts), 2 = 3 octets (16 millions d'ID, jusqu'à 21 sauts). Les versions 1.13 et antérieures utilisent des chemins multi-octets ; à partir de la version 1.14, cela n'est plus nécessaire.",
"repeater_pathHashModeHelper": "Octets utilisés pour encoder l'ID de ce répéteur dans les balises de chemin flood/détection de boucle. 0=1 octet (256 ID, jusqu'à 64 sauts), 1=2 octets (65 000 ID, jusqu'à 32 sauts), 2=3 octets (16 millions d'ID, jusqu'à 21 sauts). Le firmware antérieur à v1.14 utilisait toujours des chemins d'1 octet; v1.14 et les versions ultérieures peuvent être configurées pour des chemins de 2 ou 3 octets.",
"repeater_txDelay": "Retard dû aux inondations à Texas",
"repeater_txDelayHelper": "Rétransmettre l'espacement pour le trafic de secours en cas de inondation, en multipliant le temps d'émission du paquet (0-2, valeur par défaut : 0,5). Une valeur plus élevée signifie moins de collisions, mais une vitesse de transmission plus lente.",
"repeater_directTxDelay": "Retard de transmission direct",
+1 -1
View File
@@ -1291,7 +1291,7 @@
"repeater_advancedSettings": "Haladó",
"repeater_advancedSettingsSubtitle": "Erkélő kapcsolók tapasztalt kezelők számára",
"repeater_pathHashMode": "Út-hash mód",
"repeater_pathHashModeHelper": "A byte-ok, amelyek az alábbi repeater-ek azonosítójának kódolására szolgálnak a flood-útvonal/ciklus-észlelő címkékben. 0=1 byte (256 azonosító, akár 64 útvonal), 1=2 byte (65 000 azonosító, akár 32 útvonal), 2=3 byte (16 millió azonosító, akár 21 útvonal). A v1.13-as verziótól kezdődően és az azt követő verziókban a több byte-os útvonalak megszűntek csak egyetlen útvonal létesül, miután a hálózat a v1.14-es verzióra vagy az azt követő verzióra frissült.",
"repeater_pathHashModeHelper": "A repeater azonosítójának kódolására használt byte-ok száma a flood-útvonal/ciklusészlelési címkékben. 0=1 byte (256 azonosító, legfeljebb 64 ugrás), 1=2 byte (65 000 azonosító, legfeljebb 32 ugrás), 2=3 byte (16 millió azonosító, legfeljebb 21 ugrás). A v1.14 előtti firmware mindig 1 byte-os útvonalakat használt; a v1.14 és újabb verziók 2 vagy 3 byte-os útvonalakra is konfigurálhatók.",
"repeater_txDelay": "Flood TX késés",
"repeater_txDelayHelper": "Újraküldési intervallum árvíz esetén, amely a csomag átviteli idejének (0-2, alapérték 0,5) szorzata. Minél nagyobb az érték, annál kevesebb ütközés, de lassabb a továbbítás.",
"repeater_directTxDelay": "Közvetlen TX késés",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Avanzato",
"repeater_advancedSettingsSubtitle": "Manopole di regolazione per operatori esperti",
"repeater_pathHashMode": "Modalità di hashing del percorso",
"repeater_pathHashModeHelper": "Byte utilizzati per codificare l'ID di questo ripetitore nei tag per il rilevamento del percorso/loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Le versioni 1.13 e precedenti utilizzano percorsi multi-byte: è necessario attivare la rete prima di utilizzare questa funzionalità (a partire dalla versione 1.14).",
"repeater_pathHashModeHelper": "Byte utilizzati per codificare l'ID di questo ripetitore nei tag di percorso flood/rilevamento loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Il firmware precedente alla v1.14 usava sempre percorsi a 1 byte; v1.14 e versioni successive possono essere configurate per percorsi a 2 o 3 byte.",
"repeater_txDelay": "Ritardo a Flood, TX",
"repeater_txDelayHelper": "Riassegnare lo spazio tra i pacchetti per gestire il traffico intenso, come un moltiplicatore del tempo di trasmissione (da 0 a 2, valore predefinito 0,5). Un valore più alto significa meno collisioni, ma una trasmissione più lenta.",
"repeater_directTxDelay": "Ritardo diretto TX",
+1 -1
View File
@@ -1291,7 +1291,7 @@
"repeater_advancedSettings": "高度な",
"repeater_advancedSettingsSubtitle": "経験豊富なオペレーター向けの調整ノブ",
"repeater_pathHashMode": "パスハッシュモード",
"repeater_pathHashModeHelper": "このリピーターのIDをフローパス/ループ検出タグにエンコードするために使用されるバイト数。 0=1バイト (256個のID、最大64ホップ)、1=2バイト (65,000個のID、最大32ホップ)、2=3バイト (160万個のID、最大21ホップ)。 v1.13およびそれ以前のファームウェアでは、マルチバイトパスがサポートされていません。 v1.14以降のバージョンでは、一度ネットワークが起動されると、パスが一度だけ検出されます。",
"repeater_pathHashModeHelper": "このリピーターのIDをフラッド経路/ループ検出タグにエンコードするために使用るバイト数。0=1バイト (256 ID、最大64ホップ)、1=2バイト (65,000 ID、最大32ホップ)、2=3バイト (1,600万 ID、最大21ホップ)。v1.14より前のファームウェアは常に1バイト経路を使用していました。v1.14以降は2バイトまたは3バイト経路に設定できます。",
"repeater_txDelay": "フロイド・TXでの遅延",
"repeater_txDelayHelper": "洪水時の交通量に対応するための再送信間隔を、パケットの通信時間を掛けた値(0~2、デフォルト0.5)で設定します。値を大きくすると衝突が減りますが、通信速度が遅くなります。",
"repeater_directTxDelay": "直接的なTX遅延",
+1 -1
View File
@@ -1291,7 +1291,7 @@
"repeater_advancedSettings": "고급",
"repeater_advancedSettingsSubtitle": "숙련된 운영자를 위한 조절 노브",
"repeater_pathHashMode": "패스 해시 모드",
"repeater_pathHashModeHelper": "이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수: 0=1 바이트 (256개 ID, 최대 64개의 홉), 1=2 바이트 (65,000개 ID, 최대 32개의 홉), 2=3 바이트 (16백만 개 ID, 최대 21개의 홉). v1.13 및 이전 버전의 펌웨어는 다중 바이트 경로를 지원하지 않으며, 네트워크가 v1.14 이상으로 업그레이드되면 한 번만 감지합니다.",
"repeater_pathHashModeHelper": "이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수입니다. 0=1바이트(256개 ID, 최대 64홉), 1=2바이트(65,000개 ID, 최대 32홉), 2=3바이트(1,600만 개 ID, 최대 21홉). v1.14 이전 펌웨어는 항상 1바이트 경로를 사용했으며, v1.14 이상은 2바이트 또는 3바이트 경로로 설정할 수 있습니다.",
"repeater_txDelay": "플러드 TX 지연",
"repeater_txDelayHelper": "홍수 시 교통량에 맞춰 재전송 간격을 설정합니다. 이는 패킷의 전송 시간을 곱한 값 (0-2, 기본값 0.5)으로 설정합니다. 값이 클수록 충돌이 줄어들지만 전송 속도가 느려집니다.",
"repeater_directTxDelay": "직접적인 TX 지연",
+1 -1
View File
@@ -4493,7 +4493,7 @@ abstract class AppLocalizations {
/// No description provided for @repeater_pathHashModeHelper.
///
/// In en, this message translates to:
/// **'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.'**
/// **'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). Firmware before v1.14 always used 1-byte paths; v1.14 and newer can be configured for 2- or 3-byte paths.'**
String get repeater_pathHashModeHelper;
/// No description provided for @repeater_txDelay.
+1 -1
View File
@@ -2524,7 +2524,7 @@ class AppLocalizationsBg extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Байтовете, използвани за кодиране на идентификатора на този репитер в таговете за откриване на потоци/цикли, са: 0=1 байт (256 идентификатора, до 64 скача), 1=2 байта (65 000 идентификатора, до 32 скача), 2=3 байта (16 милиона идентификатора, до 21 скача). Версии 1.13 и по-стари версии на фърмуера използват многобайтови пътища – само след като мрежата е актуализирана до версия 1.14 или по-нова.';
'Байтовете, използвани за кодиране на идентификатора на този репитер в таговете за flood път/откриване на цикли. 0=1 байт (256 идентификатора, до 64 скока), 1=2 байта (65 000 идентификатора, до 32 скока), 2=3 байта (16 милиона идентификатора, до 21 скока). Фърмуер преди v1.14 винаги използва 1-байтови пътища; v1.14 и по-нови версии могат да се конфигурират за 2- или 3-байтови пътища.';
@override
String get repeater_txDelay => 'Забавяне на проекта \"Flood TX\"';
+1 -1
View File
@@ -2523,7 +2523,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware-Versionen 1.13 und älter verwenden mehrstellige Pfade ab Version 1.14+ wird nur ein Pfad erstellt, sobald das Netzwerk aktiv ist.';
'Bytes, die zur Kodierung der ID dieses Repeaters in Flood-Pfad-/Schleifen-Erkennung-Tags verwendet werden. 0 = 1 Byte (256 IDs, bis zu 64 Hops), 1 = 2 Bytes (65.000 IDs, bis zu 32 Hops), 2 = 3 Bytes (16 Millionen IDs, bis zu 21 Hops). Firmware vor v1.14 verwendet immer 1-Byte-Pfade; ab v1.14 können 2- oder 3-Byte-Pfade eingestellt werden.';
@override
String get repeater_txDelay => 'Verzögerung bei Flood TX';
+1 -1
View File
@@ -2470,7 +2470,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). v1.13 and older firmware drops multi-byte paths — only raise once your network is on v1.14+.';
'Bytes used to encode this repeater\'s ID in flood path/loop-detect tags. 0=1 byte (256 IDs, up to 64 hops), 1=2 bytes (65K IDs, up to 32 hops), 2=3 bytes (16M IDs, up to 21 hops). Firmware before v1.14 always used 1-byte paths; v1.14 and newer can be configured for 2- or 3-byte paths.';
@override
String get repeater_txDelay => 'Flood TX delay';
+1 -1
View File
@@ -2519,7 +2519,7 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). Las versiones 1.13 y anteriores de firmware eliminan rutas de múltiples bytes; solo se detectan una vez que la red está activa en la versión 1.14 o posterior.';
'Bytes utilizados para codificar el ID de este repetidor en las etiquetas de ruta flood/detección de bucles. 0=1 byte (256 IDs, hasta 64 saltos), 1=2 bytes (65.000 IDs, hasta 32 saltos), 2=3 bytes (16 millones de IDs, hasta 21 saltos). El firmware anterior a v1.14 siempre usaba rutas de 1 byte; v1.14 y posteriores pueden configurarse para rutas de 2 o 3 bytes.';
@override
String get repeater_txDelay => 'Retraso en Flood, TX';
+1 -1
View File
@@ -2537,7 +2537,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Octets utilisés pour encoder l\'ID de ce routeur dans les balises de détection de flux/boucles. 0 = 1 octet (256 ID, jusqu\'à 64 sauts), 1 = 2 octets (65 000 ID, jusqu\'à 32 sauts), 2 = 3 octets (16 millions d\'ID, jusqu\'à 21 sauts). Les versions 1.13 et antérieures utilisent des chemins multi-octets ; à partir de la version 1.14, cela n\'est plus nécessaire.';
'Octets utilisés pour encoder l\'ID de ce répéteur dans les balises de chemin flood/détection de boucle. 0=1 octet (256 ID, jusqu\'à 64 sauts), 1=2 octets (65 000 ID, jusqu\'à 32 sauts), 2=3 octets (16 millions d\'ID, jusqu\'à 21 sauts). Le firmware antérieur à v1.14 utilisait toujours des chemins d\'1 octet; v1.14 et les versions ultérieures peuvent être configurées pour des chemins de 2 ou 3 octets.';
@override
String get repeater_txDelay => 'Retard dû aux inondations à Texas';
+1 -1
View File
@@ -2530,7 +2530,7 @@ class AppLocalizationsHu extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'A byte-ok, amelyek az alábbi repeater-ek azonosítójának kódolására szolgálnak a flood-útvonal/ciklus-észlelő címkékben. 0=1 byte (256 azonosító, akár 64 útvonal), 1=2 byte (65 000 azonosító, akár 32 útvonal), 2=3 byte (16 millió azonosító, akár 21 útvonal). A v1.13-as verziótól kezdődően és az azt követő verziókban a több byte-os útvonalak megszűntek csak egyetlen útvonal létesül, miután a hálózat a v1.14-es verzióra vagy az azt követő verzióra frissült.';
'A repeater azonosítójának kódolására használt byte-ok száma a flood-útvonal/ciklusészlelési címkékben. 0=1 byte (256 azonosító, legfeljebb 64 ugrás), 1=2 byte (65 000 azonosító, legfeljebb 32 ugrás), 2=3 byte (16 millió azonosító, legfeljebb 21 ugrás). A v1.14 előtti firmware mindig 1 byte-os útvonalakat használt; a v1.14 és újabb verziók 2 vagy 3 byte-os útvonalakra is konfigurálhatók.';
@override
String get repeater_txDelay => 'Flood TX késés';
+1 -1
View File
@@ -2523,7 +2523,7 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Byte utilizzati per codificare l\'ID di questo ripetitore nei tag per il rilevamento del percorso/loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Le versioni 1.13 e precedenti utilizzano percorsi multi-byte: è necessario attivare la rete prima di utilizzare questa funzionalità (a partire dalla versione 1.14).';
'Byte utilizzati per codificare l\'ID di questo ripetitore nei tag di percorso flood/rilevamento loop. 0=1 byte (256 ID, fino a 64 salti), 1=2 byte (65.000 ID, fino a 32 salti), 2=3 byte (16 milioni di ID, fino a 21 salti). Il firmware precedente alla v1.14 usava sempre percorsi a 1 byte; v1.14 e versioni successive possono essere configurate per percorsi a 2 o 3 byte.';
@override
String get repeater_txDelay => 'Ritardo a Flood, TX';
+1 -1
View File
@@ -2408,7 +2408,7 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'このリピーターのIDをフローパス/ループ検出タグにエンコードするために使用されるバイト数。 0=1バイト (256個のID、最大64ホップ)、1=2バイト (65,000個のID、最大32ホップ)、2=3バイト (160万個のID、最大21ホップ)。 v1.13およびそれ以前のファームウェアでは、マルチバイトパスがサポートされていません。 v1.14以降のバージョンでは、一度ネットワークが起動されると、パスが一度だけ検出されます。';
'このリピーターのIDをフラッド経路/ループ検出タグにエンコードするために使用るバイト数。0=1バイト (256 ID、最大64ホップ)、1=2バイト (65,000 ID、最大32ホップ)、2=3バイト (1,600万 ID、最大21ホップ)。v1.14より前のファームウェアは常に1バイト経路を使用していました。v1.14以降は2バイトまたは3バイト経路に設定できます。';
@override
String get repeater_txDelay => 'フロイド・TXでの遅延';
+1 -1
View File
@@ -2407,7 +2407,7 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수: 0=1 바이트 (256개 ID, 최대 64개의 홉), 1=2 바이트 (65,000개 ID, 최대 32개의 홉), 2=3 바이트 (16백만 개 ID, 최대 21개의 홉). v1.13 및 이전 버전의 펌웨어는 다중 바이트 경로를 지원하지 않으며, 네트워크가 v1.14 이상으로 업그레이드되면 한 번만 감지합니다.';
'이 리피터의 ID를 플러드 경로/루프 감지 태그에 인코딩하는 데 사용되는 바이트 수입니다. 0=1바이트(256개 ID, 최대 64홉), 1=2바이트(65,000개 ID, 최대 32홉), 2=3바이트(1,600만 개 ID, 최대 21홉). v1.14 이전 펌웨어는 항상 1바이트 경로를 사용했으며, v1.14 이상은 2바이트 또는 3바이트 경로로 설정할 수 있습니다.';
@override
String get repeater_txDelay => '플러드 TX 지연';
+1 -1
View File
@@ -2502,7 +2502,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID\'s, tot 64 hops), 1=2 bytes (65.000 ID\'s, tot 32 hops), 2=3 bytes (16 miljoen ID\'s, tot 21 hops). Versies 1.13 en ouder gebruiken multi-byte paden alleen na het activeren van het netwerk.';
'Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID\'s, tot 64 hops), 1=2 bytes (65.000 ID\'s, tot 32 hops), 2=3 bytes (16 miljoen ID\'s, tot 21 hops). Firmware vóór v1.14 gebruikte altijd 1-byte paden; v1.14 en nieuwer kunnen worden ingesteld op 2- of 3-byte paden.';
@override
String get repeater_txDelay => 'Vertraging bij Flood TX';
+1 -1
View File
@@ -2534,7 +2534,7 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bity wykorzystywane do kodowania identyfikatora tego urządzenia w tagach ścieżek/detekcji pętli. 0=1 bity (256 identyfikatorów, do 64 skoków), 1=2 bity (65 000 identyfikatorów, do 32 skoków), 2=3 bity (1 600 000 identyfikatorów, do 21 skoków). Wersje 1.13 i wcześniejsze nie obsługują ścieżek wielobitowych wykrywają tylko jedną, gdy sieć jest w wersji 1.14 lub nowszej.';
'Bajty ywane do kodowania identyfikatora tego repeatera w tagach ścieżki flood/wykrywania pętli. 0=1 bajt (256 identyfikatorów, do 64 skoków), 1=2 bajty (65 000 identyfikatorów, do 32 skoków), 2=3 bajty (16 milionów identyfikatorów, do 21 skoków). Firmware sprzed v1.14 zawsze używał ścieżek 1-bajtowych; v1.14 i nowsze można skonfigurować na ścieżki 2- lub 3-bajtowe.';
@override
String get repeater_txDelay => 'Opóźnienie w Flood, TX';
+1 -1
View File
@@ -2516,7 +2516,7 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Bytes utilizados para codificar o ID deste repetidor nas tags de caminho/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). As versões 1.13 e anteriores do firmware não suportam caminhos multi-byte — apenas funcionam uma vez após a ativação da rede (a partir da versão 1.14+).';
'Bytes usados para codificar o ID deste repetidor nas tags de caminho flood/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). O firmware anterior à v1.14 sempre usava caminhos de 1 byte; v1.14 e versões mais recentes podem ser configuradas para caminhos de 2 ou 3 bytes.';
@override
String get repeater_txDelay => 'Atraso na entrega em Flood, TX';
+1 -1
View File
@@ -2523,7 +2523,7 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Байты, используемые для кодирования идентификатора этого ретранслятора в тегах для обнаружения потоков/циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (1 600 000 идентификаторов, до 21 перехода). Версии прошивки v1.13 и более ранние версии не поддерживают многобайтовые пути — они поднимаются только после того, как ваша сеть будет обновлена до версии v1.14 и выше.';
'Байты, используемые для кодирования идентификатора этого ретранслятора в тегах flood-маршрута/обнаружения циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (16 миллионов идентификаторов, до 21 перехода). Прошивки до v1.14 всегда использовали 1-байтовые маршруты; v1.14 и новее можно настроить на 2- или 3-байтовые маршруты.';
@override
String get repeater_txDelay => 'Задержка в работе системы Flood TX';
+1 -1
View File
@@ -2503,7 +2503,7 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Byty použité na zakódovanie ID tohto opakovača v tagoch pre trasu/detekciu slučky. 0 = 1 bytu (256 ID, až 64 skokov), 1 = 2 byty (65 000 ID, až 32 skokov), 2 = 3 byty (16 miliónov ID, až 21 skokov). Verzie 1.13 a staršie nepodporujú viacbytové trasy fungujú len, keď je sieť aktivovaná.';
'Bajty použité na zakódovanie ID tohto opakovača v tagoch flood trasy/detekcie slučky. 0=1 bajt (256 ID, až 64 skokov), 1=2 bajty (65 000 ID, až 32 skokov), 2=3 bajty (16 miliónov ID, až 21 skokov). Firmvér pred v1.14 vždy používal 1-bajtové trasy; v1.14 a novšie možno nakonfigurovať na 2- alebo 3-bajtové trasy.';
@override
String get repeater_txDelay => 'Zpoždanie v Flood, TX';
+1 -1
View File
@@ -2498,7 +2498,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Biti, ki so bila uporabljena za kodiranje ID-ja tega releja v oznakah za zaznavanje pot/kroga, imajo naslednje velikosti: 0=1 bit (256 ID-jev, do 64 skokov), 1=2 biti (65.000 ID-jev, do 32 skokov), 2=3 biti (16 milijonov ID-jev, do 21 skokov). V različicah 1.13 in starejših se ustvarjajo večbitne poti vendar se to zgodi šele, ko je omrežje vklopljeno v različicah 1.14 in kasnejših.';
'Bajti, uporabljeni za kodiranje ID-ja tega repetitorja v oznakah flood poti/zaznavanja zank. 0=1 bajt (256 ID-jev, do 64 skokov), 1=2 bajta (65.000 ID-jev, do 32 skokov), 2=3 bajti (16 milijonov ID-jev, do 21 skokov). Vdelana programska oprema pred v1.14 je vedno uporabljala 1-bajtne poti; v1.14 in novejše je mogoče nastaviti na 2- ali 3-bajtne poti.';
@override
String get repeater_txDelay => 'Zatemnitevanje zaradi poplav v Texasu';
+1 -1
View File
@@ -2487,7 +2487,7 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Byte används för att koda denna repeaters ID i taggar för att upptäcka loopar/flödesvägar. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Versioner 1.13 och äldre har stöd för multi-byte-vägar endast en gång när nätverket är aktiverat (från och med version 1.14).';
'Byte som används för att koda denna repeaters ID i taggar för flood-väg/loopdetektering. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Firmware före v1.14 använde alltid 1-byte-vägar; v1.14 och nyare kan konfigureras för 2- eller 3-byte-vägar.';
@override
String get repeater_txDelay => 'Försening i Flood TX';
+1 -1
View File
@@ -2522,7 +2522,7 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'Байти, що використовуються для кодування ідентифікатора цього ретранслятора в тегах для виявлення потоків/петлі. 0=1 байт (256 ідентифікаторів, до 64 перехідів), 1=2 байти (65 000 ідентифікаторів, до 32 перехідів), 2=3 байти (16 мільйонів ідентифікаторів, до 21 переходу). Версії 1.13 та старіші не підтримують багатобайтні шляхи — вони активуються лише після того, як мережа буде оновлена до версії 1.14+.';
'Байти, що використовуються для кодування ідентифікатора цього ретранслятора в тегах flood-шляху/виявлення петель. 0=1 байт (256 ідентифікаторів, до 64 переходів), 1=2 байти (65 000 ідентифікаторів, до 32 переходів), 2=3 байти (16 мільйонів ідентифікаторів, до 21 переходу). Прошивки до v1.14 завжди використовували 1-байтові шляхи; v1.14 і новіші можна налаштувати на 2- або 3-байтові шляхи.';
@override
String get repeater_txDelay => 'Затримка у Flood, штат Техас';
+1 -1
View File
@@ -2362,7 +2362,7 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get repeater_pathHashModeHelper =>
'用于编码此复用器的 ID 的字节数,在“洪流路径/环检测”标签中使用。 0=1 字节(256 个 ID,最多 64 个跳跃),1=2 字节(65K 个 ID,最多 32 个跳跃),2=3 字节(16M 个 ID,最多 21 个跳跃)。 v1.13 及更早版本的固件会使用多字节路径——只有在您的网络升级到 v1.14 或更高版本后才会生效';
'用于在洪泛路径/环路检测标签中编码此中继器 ID 的字节数。0=1 字节(256 个 ID,最多 64 ),1=2 字节(65K 个 ID,最多 32 ),2=3 字节(16M 个 ID,最多 21 )。v1.14 之前的固件始终使用 1 字节路径;v1.14 及更新版本可配置为 2 或 3 字节路径';
@override
String get repeater_txDelay => '洪水(德克萨斯州)延误';
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Geavanceerd",
"repeater_advancedSettingsSubtitle": "Regelhendels voor ervaren gebruikers",
"repeater_pathHashMode": "Hash-modus voor paden",
"repeater_pathHashModeHelper": "Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID's, tot 64 hops), 1=2 bytes (65.000 ID's, tot 32 hops), 2=3 bytes (16 miljoen ID's, tot 21 hops). Versies 1.13 en ouder gebruiken multi-byte paden alleen na het activeren van het netwerk.",
"repeater_pathHashModeHelper": "Bytes die gebruikt worden om de ID van deze repeater te coderen in flood-pad/lusdetectietags. 0=1 byte (256 ID's, tot 64 hops), 1=2 bytes (65.000 ID's, tot 32 hops), 2=3 bytes (16 miljoen ID's, tot 21 hops). Firmware vóór v1.14 gebruikte altijd 1-byte paden; v1.14 en nieuwer kunnen worden ingesteld op 2- of 3-byte paden.",
"repeater_txDelay": "Vertraging bij Flood TX",
"repeater_txDelayHelper": "Herzendinterval voor verkeer tijdens overstromingen, als een veelvoud van de tijd die het pakket nodig heeft (0-2, standaard 0.5). Een hoger getal betekent minder botsingen, maar ook een langere leveringstijd.",
"repeater_directTxDelay": "Directe vertraging",
+1 -1
View File
@@ -1115,7 +1115,7 @@
"repeater_advancedSettings": "Zaawansowany",
"repeater_advancedSettingsSubtitle": "Regulowane pokrętła dla doświadczonych operatorów",
"repeater_pathHashMode": "Tryb haszujący ścieżkę",
"repeater_pathHashModeHelper": "Bity wykorzystywane do kodowania identyfikatora tego urządzenia w tagach ścieżek/detekcji pętli. 0=1 bity (256 identyfikatorów, do 64 skoków), 1=2 bity (65 000 identyfikatorów, do 32 skoków), 2=3 bity (1 600 000 identyfikatorów, do 21 skoków). Wersje 1.13 i wcześniejsze nie obsługują ścieżek wielobitowych wykrywają tylko jedną, gdy sieć jest w wersji 1.14 lub nowszej.",
"repeater_pathHashModeHelper": "Bajty ywane do kodowania identyfikatora tego repeatera w tagach ścieżki flood/wykrywania pętli. 0=1 bajt (256 identyfikatorów, do 64 skoków), 1=2 bajty (65 000 identyfikatorów, do 32 skoków), 2=3 bajty (16 milionów identyfikatorów, do 21 skoków). Firmware sprzed v1.14 zawsze używał ścieżek 1-bajtowych; v1.14 i nowsze można skonfigurować na ścieżki 2- lub 3-bajtowe.",
"repeater_txDelay": "Opóźnienie w Flood, TX",
"repeater_txDelayHelper": "Ustawienie odstępu dla ruchu związanego z powodzią, jako mnożnik czasu przesyłania pakietu (0-2, domyślnie 0,5). Wyższe wartości oznaczają mniejszą liczbę kolizji, ale wolniejszą prędkość przesyłania.",
"repeater_directTxDelay": "Bezpośrednie opóźnienie sygnału TX",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Avançado",
"repeater_advancedSettingsSubtitle": "Controles de ajuste para operadores experientes",
"repeater_pathHashMode": "Modo de hash de caminho",
"repeater_pathHashModeHelper": "Bytes utilizados para codificar o ID deste repetidor nas tags de caminho/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). As versões 1.13 e anteriores do firmware não suportam caminhos multi-byte — apenas funcionam uma vez após a ativação da rede (a partir da versão 1.14+).",
"repeater_pathHashModeHelper": "Bytes usados para codificar o ID deste repetidor nas tags de caminho flood/detecção de loop. 0=1 byte (256 IDs, até 64 saltos), 1=2 bytes (65.000 IDs, até 32 saltos), 2=3 bytes (16 milhões de IDs, até 21 saltos). O firmware anterior à v1.14 sempre usava caminhos de 1 byte; v1.14 e versões mais recentes podem ser configuradas para caminhos de 2 ou 3 bytes.",
"repeater_txDelay": "Atraso na entrega em Flood, TX",
"repeater_txDelayHelper": "Ajuste de espaçamento para tráfego de inundações, como um multiplicador do tempo de transmissão (0-2, padrão 0,5). Quanto maior, menos colisões, mas uma entrega mais lenta.",
"repeater_directTxDelay": "Atraso direto no sinal TX",
+1 -1
View File
@@ -1436,7 +1436,7 @@
"repeater_advancedSettings": "Продвинутый",
"repeater_advancedSettingsSubtitle": "Регуляторы для опытных операторов",
"repeater_pathHashMode": "Режим хеширования пути",
"repeater_pathHashModeHelper": "Байты, используемые для кодирования идентификатора этого ретранслятора в тегах для обнаружения потоков/циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (1 600 000 идентификаторов, до 21 перехода). Версии прошивки v1.13 и более ранние версии не поддерживают многобайтовые пути — они поднимаются только после того, как ваша сеть будет обновлена до версии v1.14 и выше.",
"repeater_pathHashModeHelper": "Байты, используемые для кодирования идентификатора этого ретранслятора в тегах flood-маршрута/обнаружения циклов. 0 = 1 байт (256 идентификаторов, до 64 переходов), 1 = 2 байта (65 000 идентификаторов, до 32 переходов), 2 = 3 байта (16 миллионов идентификаторов, до 21 перехода). Прошивки до v1.14 всегда использовали 1-байтовые маршруты; v1.14 и новее можно настроить на 2- или 3-байтовые маршруты.",
"repeater_txDelay": "Задержка в работе системы Flood TX",
"repeater_txDelayHelper": "Передача с увеличенным интервалом для трафика во время наводнения, в качестве коэффициента, умножающего время передачи пакета (от 0 до 2, по умолчанию 0,5). Более высокое значение означает меньшее количество столкновений, но более медленную передачу.",
"repeater_directTxDelay": "Прямая задержка сигнала TX",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Pokročilé",
"repeater_advancedSettingsSubtitle": "Ovládacie knopy pre skúsených operátorov",
"repeater_pathHashMode": "Režim hashovania cesty",
"repeater_pathHashModeHelper": "Byty použité na zakódovanie ID tohto opakovača v tagoch pre trasu/detekciu slučky. 0 = 1 bytu (256 ID, až 64 skokov), 1 = 2 byty (65 000 ID, až 32 skokov), 2 = 3 byty (16 miliónov ID, až 21 skokov). Verzie 1.13 a staršie nepodporujú viacbytové trasy fungujú len, keď je sieť aktivovaná.",
"repeater_pathHashModeHelper": "Bajty použité na zakódovanie ID tohto opakovača v tagoch flood trasy/detekcie slučky. 0=1 bajt (256 ID, až 64 skokov), 1=2 bajty (65 000 ID, až 32 skokov), 2=3 bajty (16 miliónov ID, až 21 skokov). Firmvér pred v1.14 vždy používal 1-bajtové trasy; v1.14 a novšie možno nakonfigurovať na 2- alebo 3-bajtové trasy.",
"repeater_txDelay": "Zpoždanie v Flood, TX",
"repeater_txDelayHelper": "Nastavenie pre opakované vysielanie pre dopravu počas povodní, ako násobok času, ktorý paket využije (0-2, výchoce hodnota 0,5). Vyššia hodnota znamená menej kolízii, ale pomalšie doručovanie.",
"repeater_directTxDelay": "Priame oneskorenie TX",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Napredno",
"repeater_advancedSettingsSubtitle": "Gumbi za nastavljanje za izkušene uporabnike",
"repeater_pathHashMode": "Način ustvarjanja hash-a poti",
"repeater_pathHashModeHelper": "Biti, ki so bila uporabljena za kodiranje ID-ja tega releja v oznakah za zaznavanje pot/kroga, imajo naslednje velikosti: 0=1 bit (256 ID-jev, do 64 skokov), 1=2 biti (65.000 ID-jev, do 32 skokov), 2=3 biti (16 milijonov ID-jev, do 21 skokov). V različicah 1.13 in starejših se ustvarjajo večbitne poti vendar se to zgodi šele, ko je omrežje vklopljeno v različicah 1.14 in kasnejših.",
"repeater_pathHashModeHelper": "Bajti, uporabljeni za kodiranje ID-ja tega repetitorja v oznakah flood poti/zaznavanja zank. 0=1 bajt (256 ID-jev, do 64 skokov), 1=2 bajta (65.000 ID-jev, do 32 skokov), 2=3 bajti (16 milijonov ID-jev, do 21 skokov). Vdelana programska oprema pred v1.14 je vedno uporabljala 1-bajtne poti; v1.14 in novejše je mogoče nastaviti na 2- ali 3-bajtne poti.",
"repeater_txDelay": "Zatemnitevanje zaradi poplav v Texasu",
"repeater_txDelayHelper": "Uporaba intervalov za ponovno pošiljanje v primeru prometa zaradi poplav, kot pomnožnik časovne trajanje paketa (0-2, privzeto 0,5). Veje vrednost = manjše kolizije, vendar počasnejše dostavo.",
"repeater_directTxDelay": "Neposredni časovno odlašanje",
+1 -1
View File
@@ -1105,7 +1105,7 @@
"repeater_advancedSettings": "Avancerad",
"repeater_advancedSettingsSubtitle": "Ställjusteringsknappar för erfarna användare",
"repeater_pathHashMode": "Hash-läge för sökväg",
"repeater_pathHashModeHelper": "Byte används för att koda denna repeaters ID i taggar för att upptäcka loopar/flödesvägar. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Versioner 1.13 och äldre har stöd för multi-byte-vägar endast en gång när nätverket är aktiverat (från och med version 1.14).",
"repeater_pathHashModeHelper": "Byte som används för att koda denna repeaters ID i taggar för flood-väg/loopdetektering. 0=1 byte (256 ID:n, upp till 64 hopp), 1=2 byte (65 000 ID:n, upp till 32 hopp), 2=3 byte (16 miljoner ID:n, upp till 21 hopp). Firmware före v1.14 använde alltid 1-byte-vägar; v1.14 och nyare kan konfigureras för 2- eller 3-byte-vägar.",
"repeater_txDelay": "Försening i Flood TX",
"repeater_txDelayHelper": "Återöverföringsintervall för trafik under perioder med hög belastning, som en multiplikator av paketets överföringstid (0-2, standard 0,5). Högre värde = färre kollisioner, men långsammare leverans.",
"repeater_directTxDelay": "Direkt TX-fördröjning",
+1 -1
View File
@@ -1115,7 +1115,7 @@
"repeater_advancedSettings": "Просунутий",
"repeater_advancedSettingsSubtitle": "Регулювальні ручки для досвідчених операторів",
"repeater_pathHashMode": "Режим хешування шляху",
"repeater_pathHashModeHelper": "Байти, що використовуються для кодування ідентифікатора цього ретранслятора в тегах для виявлення потоків/петлі. 0=1 байт (256 ідентифікаторів, до 64 перехідів), 1=2 байти (65 000 ідентифікаторів, до 32 перехідів), 2=3 байти (16 мільйонів ідентифікаторів, до 21 переходу). Версії 1.13 та старіші не підтримують багатобайтні шляхи — вони активуються лише після того, як мережа буде оновлена до версії 1.14+.",
"repeater_pathHashModeHelper": "Байти, що використовуються для кодування ідентифікатора цього ретранслятора в тегах flood-шляху/виявлення петель. 0=1 байт (256 ідентифікаторів, до 64 переходів), 1=2 байти (65 000 ідентифікаторів, до 32 переходів), 2=3 байти (16 мільйонів ідентифікаторів, до 21 переходу). Прошивки до v1.14 завжди використовували 1-байтові шляхи; v1.14 і новіші можна налаштувати на 2- або 3-байтові шляхи.",
"repeater_txDelay": "Затримка у Flood, штат Техас",
"repeater_txDelayHelper": "Повторне надсилання з урахуванням навантаження від потоків транспорту, як множник від часу передачі пакета (0-2, за замовчуванням 0,5). Чим вище значення, тим менше конфліктів, але повільніше передавання.",
"repeater_directTxDelay": "Пряме затримка TX",
+1 -1
View File
@@ -1135,7 +1135,7 @@
"repeater_advancedSettings": "高级",
"repeater_advancedSettingsSubtitle": "高级操作员使用的调节旋钮",
"repeater_pathHashMode": "路径哈希模式",
"repeater_pathHashModeHelper": "用于编码此复用器的 ID 的字节数,在“洪流路径/环检测”标签中使用。 0=1 字节(256 个 ID,最多 64 个跳跃),1=2 字节(65K 个 ID,最多 32 个跳跃),2=3 字节(16M 个 ID,最多 21 个跳跃)。 v1.13 及更早版本的固件会使用多字节路径——只有在您的网络升级到 v1.14 或更高版本后才会生效。",
"repeater_pathHashModeHelper": "用于在洪泛路径/环路检测标签中编码此中继器 ID 的字节数。0=1 字节(256 个 ID,最多 64 ),1=2 字节(65K 个 ID,最多 32 ),2=3 字节(16M 个 ID,最多 21 )。v1.14 之前的固件始终使用 1 字节路径;v1.14 及更新版本可配置为 2 或 3 字节路径。",
"repeater_txDelay": "洪水(德克萨斯州)延误",
"repeater_txDelayHelper": "对于洪水流量,重新传输间隔应设置为包的传输时间(0-2,默认值为0.5)的倍数。 较高的值意味着更少的冲突,但传输速度会变慢。",
"repeater_directTxDelay": "直接的 TX 延迟",
+13 -5
View File
@@ -13,6 +13,7 @@ import '../helpers/chat_scroll_controller.dart';
import '../connector/meshcore_protocol.dart';
import '../helpers/cyr2lat.dart';
import '../helpers/gif_helper.dart';
import '../helpers/path_helper.dart';
import '../helpers/reaction_helper.dart';
import '../helpers/snack_bar_builder.dart';
import '../l10n/l10n.dart';
@@ -422,6 +423,9 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
: (message.pathVariants.isNotEmpty
? message.pathVariants.first
: Uint8List(0));
final displayPathHashWidth =
message.pathHashWidth ??
context.read<MeshCoreConnector>().pathHashByteWidth;
const maxSwipeOffset = 64.0;
const replySwipeThreshold = 64.0;
@@ -608,7 +612,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
: EdgeInsets.zero,
child: Text(
context.l10n.channels_via(
_formatPathPrefixes(displayPath),
_formatPathPrefixes(
displayPath,
displayPathHashWidth,
),
),
style: TextStyle(
fontSize: 11,
@@ -1432,10 +1439,11 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
);
}
String _formatPathPrefixes(Uint8List pathBytes) {
return pathBytes
.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase())
.join(',');
String _formatPathPrefixes(Uint8List pathBytes, int pathHashByteWidth) {
return PathHelper.splitPathBytes(
pathBytes,
pathHashByteWidth,
).map(PathHelper.formatHopHex).join(',');
}
}
+25 -17
View File
@@ -488,11 +488,17 @@ class _ChannelMessagePathMapScreenState
? Uint8List.fromList(selectedPathTmp.reversed.toList())
: selectedPathTmp;
final selectedIndex = _indexForPath(selectedPath, observedPaths);
final width = (widget.message.pathHashWidth ?? connector.pathHashByteWidth)
.clamp(1, 4)
.toInt();
final hops = _buildPathHops(selectedPath, connector, context.l10n, width);
final width =
(widget.message.pathHashWidth ?? connector.pathHashByteWidth)
.clamp(1, 4)
.toInt();
final selectedIndex = _indexForPath(selectedPathTmp, observedPaths);
final hops = _buildPathHops(
selectedPath,
connector,
context.l10n,
width,
);
final points = <LatLng>[];
@@ -610,14 +616,18 @@ class _ChannelMessagePathMapScreenState
bounds: bounds,
),
if (observedPaths.length > 1)
_buildPathSelector(context, observedPaths, selectedIndex, (
index,
) {
setState(() {
_selectedPath = observedPaths[index].pathBytes;
_focusedHopIndex = null;
});
}),
_buildPathSelector(
context,
observedPaths,
selectedIndex,
width,
(index) {
setState(() {
_selectedPath = observedPaths[index].pathBytes;
_focusedHopIndex = null;
});
},
),
if (points.isEmpty)
Center(
child: Card(
@@ -643,13 +653,11 @@ class _ChannelMessagePathMapScreenState
BuildContext context,
List<_ObservedPath> paths,
int selectedIndex,
int hashByteWidth,
ValueChanged<int> onSelected,
) {
final l10n = context.l10n;
final width = context.read<MeshCoreConnector>().pathHashByteWidth.clamp(
1,
4,
);
final width = hashByteWidth.clamp(1, 4);
final selectedPath = paths[selectedIndex];
final label = selectedPath.isPrimary
? l10n.channelPath_primaryPath(selectedIndex + 1)
+12 -6
View File
@@ -805,16 +805,22 @@ class _ChatScreenState extends State<ChatScreen> {
pathsWithRepeaters = paths.map((path) {
final isDirectRepeater =
directRepeater != null &&
path.pathBytes.isNotEmpty &&
directRepeater.pubkeyFirstByte == path.pathBytes.first;
directRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
final isSecondDirectRepeater =
secondDirectRepeater != null &&
path.pathBytes.isNotEmpty &&
secondDirectRepeater.pubkeyFirstByte == path.pathBytes.first;
secondDirectRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
final isThirdDirectRepeater =
thirdDirectRepeater != null &&
path.pathBytes.isNotEmpty &&
thirdDirectRepeater.pubkeyFirstByte == path.pathBytes.first;
thirdDirectRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
int ranking = -1;
Color color = Colors.grey;
+12 -2
View File
@@ -1266,7 +1266,7 @@ class _ContactsScreenState extends State<ContactsScreen>
MaterialPageRoute(
builder: (context) => PathTraceMapScreen(
title: context.l10n.contacts_repeaterPing,
path: Uint8List.fromList([contact.publicKey.first]),
path: _contactPathPrefix(contact, hw),
targetContact: contact,
pathHashByteWidth: hw,
),
@@ -1299,7 +1299,7 @@ class _ContactsScreenState extends State<ContactsScreen>
: context.l10n.contacts_roomPing,
path: contact.pathBytesForDisplay.isNotEmpty
? contact.pathBytesForDisplay
: Uint8List.fromList([contact.publicKey.first]),
: _contactPathPrefix(contact, hw),
flipPathAround: contact.pathBytesForDisplay.isNotEmpty,
targetContact: contact,
pathHashByteWidth: hw,
@@ -1416,6 +1416,16 @@ class _ContactsScreenState extends State<ContactsScreen>
);
}
Uint8List _contactPathPrefix(Contact contact, int hashByteWidth) {
if (contact.publicKey.isEmpty) return Uint8List(0);
final width = hashByteWidth
.clamp(1, pubKeySize)
.toInt()
.clamp(1, contact.publicKey.length)
.toInt();
return Uint8List.fromList(contact.publicKey.sublist(0, width));
}
void _confirmDelete(
BuildContext context,
MeshCoreConnector connector,
+15 -2
View File
@@ -728,7 +728,10 @@ class _MapScreenState extends State<MapScreen> {
for (final repeater in withLocation) {
if (repeater.type != advTypeRepeater) continue;
if (repeater.publicKey.length < lastHop.length) continue;
if (!listEquals(repeater.publicKey.sublist(0, lastHop.length), lastHop)) {
if (!listEquals(
repeater.publicKey.sublist(0, lastHop.length),
lastHop,
)) {
continue;
}
anchorSet.add(LatLng(repeater.latitude!, repeater.longitude!));
@@ -986,11 +989,21 @@ class _MapScreenState extends State<MapScreen> {
}
if (settings.mapShowOverlaps) {
final hopWidth = context
.read<MeshCoreConnector>()
.pathHashByteWidth
.clamp(1, pubKeySize)
.toInt();
final hasOverlap = contacts
.where(
(c) =>
c.publicKeyHex != contact.publicKeyHex &&
c.publicKey.first == contact.publicKey.first &&
c.publicKey.length >= hopWidth &&
contact.publicKey.length >= hopWidth &&
listEquals(
c.publicKey.sublist(0, hopWidth),
contact.publicKey.sublist(0, hopWidth),
) &&
(c.type == advTypeRepeater || c.type == advTypeRoom) &&
(contact.type == advTypeRepeater ||
contact.type == advTypeRoom),
+84
View File
@@ -298,6 +298,15 @@ class _SettingsScreenState extends State<SettingsScreen> {
onTap: () => pushCompanionRadioStatsScreen(context),
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.route_outlined),
title: Text(l10n.repeater_pathHashMode),
subtitle: Text(_pathHashModeSubtitle(connector.pathHashByteWidth)),
trailing: const Icon(Icons.chevron_right),
enabled: connector.isConnected,
onTap: () => _editPathHashMode(context, connector),
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.location_on_outlined),
title: Text(l10n.settings_location),
@@ -338,6 +347,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
String _pathHashModeSubtitle(int pathHashByteWidth) {
final width = pathHashByteWidth.clamp(1, 3).toInt();
final mode = width - 1;
final unit = width == 1 ? 'byte' : 'bytes';
return 'Mode $mode - $width $unit per hop';
}
Widget _buildActionsCard(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
return Card(
@@ -545,6 +561,74 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
void _editPathHashMode(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
var selectedMode = (connector.pathHashByteWidth - 1).clamp(0, 2).toInt();
showDialog(
context: context,
builder: (dialogContext) => StatefulBuilder(
builder: (context, setDialogState) => AlertDialog(
title: Text(l10n.repeater_pathHashMode),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DropdownButtonFormField<int>(
initialValue: selectedMode,
decoration: InputDecoration(
labelText: l10n.repeater_pathHashMode,
border: const OutlineInputBorder(),
),
items: const [
DropdownMenuItem(value: 0, child: Text('0 - 1 byte')),
DropdownMenuItem(value: 1, child: Text('1 - 2 bytes')),
DropdownMenuItem(value: 2, child: Text('2 - 3 bytes')),
],
onChanged: (value) {
if (value == null) return;
setDialogState(() => selectedMode = value);
},
),
const SizedBox(height: 12),
Text(
l10n.repeater_pathHashModeHelper,
style: Theme.of(context).textTheme.bodySmall,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(l10n.common_cancel),
),
FilledButton(
onPressed: () async {
Navigator.pop(dialogContext);
try {
await connector.setPathHashMode(selectedMode);
await connector.refreshDeviceInfo();
if (!context.mounted) return;
showDismissibleSnackBar(
context,
content: Text(l10n.repeater_settingsSaved),
);
} catch (e) {
if (!context.mounted) return;
showDismissibleSnackBar(
context,
content: Text(l10n.settings_error(e.toString())),
);
}
},
child: Text(l10n.common_save),
),
],
),
),
);
}
void _editLocation(BuildContext context, MeshCoreConnector connector) {
final l10n = context.l10n;
final latController = TextEditingController();
+12 -6
View File
@@ -202,16 +202,22 @@ class _PathManagementDialogState extends State<_PathManagementDialog> {
paths.map((path) {
final isDirectRepeater =
directRepeater != null &&
path.pathBytes.isNotEmpty &&
directRepeater.pubkeyFirstByte == path.pathBytes.first;
directRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
final isSecondDirectRepeater =
secondDirectRepeater != null &&
path.pathBytes.isNotEmpty &&
secondDirectRepeater.pubkeyFirstByte == path.pathBytes.first;
secondDirectRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
final isThirdDirectRepeater =
thirdDirectRepeater != null &&
path.pathBytes.isNotEmpty &&
thirdDirectRepeater.pubkeyFirstByte == path.pathBytes.first;
thirdDirectRepeater.matchesPathStart(
path.pathBytes,
connector.pathHashByteWidth,
);
int ranking = -1;
Color color = Colors.grey;
+24 -11
View File
@@ -1,23 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
import '../connector/meshcore_connector.dart';
import '../connector/meshcore_protocol.dart';
import '../helpers/path_helper.dart';
import '../l10n/l10n.dart';
import '../models/contact.dart';
import 'signal_ui.dart';
Contact? _getRepeaterPrefixMatchNearLocation(
List<Contact> contacts,
int pubkeyFirstByte, {
List<int> pubkeyPrefix, {
String? contactKeyHex,
LatLng? searchPoint,
bool preferFavorites = false,
}) {
if (contactKeyHex != null) {
for (final c in contacts) {
if (c.publicKeyHex == contactKeyHex) {
return c;
}
}
}
final candidates = contacts
.where(
(c) =>
c.publicKey.isNotEmpty &&
c.publicKey.first == pubkeyFirstByte &&
c.publicKey.length >= pubkeyPrefix.length &&
listEquals(
c.publicKey.sublist(0, pubkeyPrefix.length),
pubkeyPrefix,
) &&
(c.type == advTypeRepeater || c.type == advTypeRoom),
)
.toList();
@@ -162,7 +176,7 @@ class _SNRIndicatorState extends State<SNRIndicator> {
),
if (directRepeater != null)
Text(
'${directRepeaters.length}: ${directRepeater.pubkeyFirstByte.toRadixString(16).padLeft(2, '0')}: ${_formatLastUpdated(directRepeater.lastUpdated)}',
'${directRepeaters.length}: ${directRepeater.pubkeyPrefixHex}: ${_formatLastUpdated(directRepeater.lastUpdated)}',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
@@ -236,23 +250,22 @@ class _SNRIndicatorState extends State<SNRIndicator> {
final contact = _getRepeaterPrefixMatchNearLocation(
allContacts,
repeater.pubkeyFirstByte,
repeater.pubkeyPrefix,
contactKeyHex: repeater.contactKeyHex,
searchPoint: selfPoint,
preferFavorites: true,
);
final name = contact?.name;
final prefixLabel = PathHelper.formatHopHex(
repeater.pubkeyPrefix,
);
return Column(
children: [
ListTile(
leading: Icon(snrUi.icon, color: snrUi.color),
title: Text(
name ??
repeater.pubkeyFirstByte
.toRadixString(16)
.padLeft(2, '0'),
),
title: Text(name ?? prefixLabel),
subtitle: Text(
'SNR: ${repeater.snr.toStringAsFixed(1)} dB\n${l10n.snrIndicator_lastSeen}: ${_formatLastUpdated(repeater.lastUpdated)}',
),