mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-06 08:46:40 +10:00
Add option for automatic zerohop adverts on posision change.
This commit is contained in:
@@ -216,6 +216,9 @@ class MeshCoreConnector extends ChangeNotifier {
|
||||
DateTime _lastRadioRxTime = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
DateTime _lastContactMsgRxTime = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
DateTime _lastChannelMsgRxTime = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
DateTime _lastZeroHopAdvertAt = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
double? _lastZeroHopAdvertLatitude;
|
||||
double? _lastZeroHopAdvertLongitude;
|
||||
static const int _radioQuietMs = 3000;
|
||||
static const int _radioQuietMaxWaitMs = 3000;
|
||||
|
||||
@@ -2523,6 +2526,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
||||
_selfName = null;
|
||||
_selfLatitude = null;
|
||||
_selfLongitude = null;
|
||||
_lastZeroHopAdvertLatitude = null;
|
||||
_lastZeroHopAdvertLongitude = null;
|
||||
_awaitingSelfInfo = false;
|
||||
_webInitialHandshakeRequestSent = false;
|
||||
_selfInfoRetryTimer?.cancel();
|
||||
@@ -2689,6 +2694,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
||||
_selfName = null;
|
||||
_selfLatitude = null;
|
||||
_selfLongitude = null;
|
||||
_lastZeroHopAdvertLatitude = null;
|
||||
_lastZeroHopAdvertLongitude = null;
|
||||
_clientRepeat = null;
|
||||
_rememberedNonRepeatRadioState = null;
|
||||
_firmwareVerCode = null;
|
||||
@@ -3797,6 +3804,11 @@ class MeshCoreConnector extends ChangeNotifier {
|
||||
Future<void> sendSelfAdvert({bool flood = true}) async {
|
||||
if (!isConnected) return;
|
||||
await sendFrame(buildSendSelfAdvertFrame(flood: flood));
|
||||
if (!flood) {
|
||||
_lastZeroHopAdvertAt = DateTime.now();
|
||||
_lastZeroHopAdvertLatitude = _selfLatitude;
|
||||
_lastZeroHopAdvertLongitude = _selfLongitude;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> rebootDevice() async {
|
||||
@@ -4260,6 +4272,42 @@ class MeshCoreConnector extends ChangeNotifier {
|
||||
tag: 'Connector',
|
||||
);
|
||||
}
|
||||
|
||||
const locationChangeEpsilon = 2.25e-4; // ~25 meters in degrees.
|
||||
final lastAdvertLatitude = _lastZeroHopAdvertLatitude;
|
||||
final lastAdvertLongitude = _lastZeroHopAdvertLongitude;
|
||||
final currentLatitude = _selfLatitude;
|
||||
final currentLongitude = _selfLongitude;
|
||||
final latChanged =
|
||||
lastAdvertLatitude != null &&
|
||||
currentLatitude != null &&
|
||||
(currentLatitude - lastAdvertLatitude).abs() >= locationChangeEpsilon;
|
||||
final lonChanged =
|
||||
lastAdvertLongitude != null &&
|
||||
currentLongitude != null &&
|
||||
(currentLongitude - lastAdvertLongitude).abs() >= locationChangeEpsilon;
|
||||
final gpsSampleChanged =
|
||||
hasValidLocation(currentLatitude, currentLongitude) &&
|
||||
(!hasValidLocation(lastAdvertLatitude, lastAdvertLongitude) ||
|
||||
latChanged ||
|
||||
lonChanged);
|
||||
final effectiveGpsIntervalSeconds =
|
||||
_appSettingsService?.resolvedGpsIntervalSeconds(_currentCustomVars) ??
|
||||
0;
|
||||
final timeSinceLastZeroHopAdvert = DateTime.now().difference(
|
||||
_lastZeroHopAdvertAt,
|
||||
);
|
||||
final shouldAutoSendZeroHopAdvert =
|
||||
(gpsSampleChanged || (_clientRepeat ?? false)) &&
|
||||
_advertLocPolicy == 1 &&
|
||||
(_appSettingsService?.settings.autoSendZeroHopAdvertOnGpsUpdate ??
|
||||
false) &&
|
||||
effectiveGpsIntervalSeconds > 0 &&
|
||||
timeSinceLastZeroHopAdvert.inSeconds >= effectiveGpsIntervalSeconds;
|
||||
if (shouldAutoSendZeroHopAdvert) {
|
||||
unawaited(sendSelfAdvert(flood: false));
|
||||
}
|
||||
|
||||
final selfName = _selfName?.trim();
|
||||
if (_activeTransport == MeshCoreTransportType.usb &&
|
||||
selfName != null &&
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Невалидна ширина или дължина.",
|
||||
"settings_latitude": "Широчина",
|
||||
"settings_longitude": "Дължина",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Автоматична zero-hop обява при GPS обновяване",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Когато GPS местоположението се промени, изпрати zero-hop обява (изисква местоположение в обявата).",
|
||||
"settings_privacyMode": "Режим на поверителност",
|
||||
"settings_privacyModeSubtitle": "Скриване на име/местоположение в рекламите",
|
||||
"settings_privacyModeToggle": "Активирайте режим на поверителност, за да скриете името и местоположението си в рекламите.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Ungültiger Breiten- oder Längengrad.",
|
||||
"settings_latitude": "Breitengrad",
|
||||
"settings_longitude": "Längengrad",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatische Zero-Hop-Ankündigung bei GPS-Update",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Wenn sich der GPS-Standort ändert, eine Zero-Hop-Ankündigung senden (erfordert Standort in der Ankündigung).",
|
||||
"settings_privacyMode": "Privatsphärenmodus",
|
||||
"settings_privacyModeSubtitle": "Name und Standort in Ankündigungen verbergen",
|
||||
"settings_privacyModeToggle": "Privatsphärenmodus aktivieren, um Namen und Standort in Ankündigungen zu verbergen.",
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
"settings_telemetryEnvironmentMode": "Telemetry Environment Mode",
|
||||
"settings_advertLocation": "Advert Location",
|
||||
"settings_advertLocationSubtitle": "Include location in advert.",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Auto Zero-Hop Advert On GPS Update",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "When GPS location changes, send a zero-hop advert (requires Advert Location).",
|
||||
"settings_multiAck": "Multi-ACKs",
|
||||
"settings_telemetryModeUpdated": "Telemetry mode updated",
|
||||
"settings_actions": "Actions",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Latitud o longitud inválidos.",
|
||||
"settings_latitude": "Latitud",
|
||||
"settings_longitude": "Longitud",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Anuncio de cero saltos automático al actualizar GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Cuando cambie la ubicación GPS, enviar un anuncio de cero saltos (requiere ubicación en anuncio).",
|
||||
"settings_privacyMode": "Modo de privacidad",
|
||||
"settings_privacyModeSubtitle": "Ocultar nombre/ubicación en anuncios",
|
||||
"settings_privacyModeToggle": "Activar el modo de privacidad para ocultar tu nombre y ubicación en los anuncios.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Latitude ou longitude invalide.",
|
||||
"settings_latitude": "Latitude",
|
||||
"settings_longitude": "Longitude",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Annonce zéro saut automatique lors de la mise à jour GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Lorsque la position GPS change, envoyer une annonce zéro saut (nécessite la position dans l'annonce).",
|
||||
"settings_privacyMode": "Mode de confidentialité",
|
||||
"settings_privacyModeSubtitle": "Masquer le nom et la localisation dans les annonces",
|
||||
"settings_privacyModeToggle": "Activez le mode confidentialité pour masquer votre nom et votre localisation dans les annonces.",
|
||||
|
||||
@@ -161,6 +161,8 @@
|
||||
"settings_locationIntervalInvalid": "Az intervallumnak legalább 60 másodpercnek kell lennie, és kevesebbnek kell lennie 86 400 másodpercnél.",
|
||||
"settings_latitude": "Szélesség",
|
||||
"settings_longitude": "Hosszúság",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatikus zero-hop hirdetés GPS-frissítéskor",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Ha a GPS-helyzet megváltozik, küldjön zero-hop hirdetést (a hirdetésben helymegadás szükséges).",
|
||||
"settings_contactSettings": "Kapcsolati beállítások",
|
||||
"settings_contactSettingsSubtitle": "A névjegyek hozzáadásának beállításai.",
|
||||
"settings_privacyMode": "Adatvédelmi mód",
|
||||
|
||||
@@ -2207,6 +2207,8 @@
|
||||
"settings_telemetryEnvironmentMode": "Modalità di ambiente di telemetria",
|
||||
"settings_advertLocation": "Posizione dell'annuncio",
|
||||
"settings_advertLocationSubtitle": "Includi la posizione nell'annuncio",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Annuncio zero-hop automatico all'aggiornamento GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Quando la posizione GPS cambia, invia un annuncio zero-hop (richiede la posizione nell'annuncio).",
|
||||
"settings_privacy": "Impostazioni sulla privacy",
|
||||
"settings_denyAll": "Negare tutto",
|
||||
"settings_privacySubtitle": "Controlla le informazioni che vengono condivise.",
|
||||
|
||||
@@ -167,6 +167,8 @@
|
||||
"settings_locationIntervalInvalid": "間隔は少なくとも60秒で、86400秒未満でなければなりません。",
|
||||
"settings_latitude": "緯度",
|
||||
"settings_longitude": "経度",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "GPS更新時にゼロホップ広告を自動送信",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "GPS位置が変化したときにゼロホップ広告を送信します(広告への位置情報の含有が必要)。",
|
||||
"settings_contactSettings": "連絡先設定",
|
||||
"settings_contactSettingsSubtitle": "連絡先の追加方法に関する設定",
|
||||
"settings_privacyMode": "プライバシーモード",
|
||||
|
||||
@@ -161,6 +161,8 @@
|
||||
"settings_locationIntervalInvalid": "간격은 최소 60초 이상, 86400초 미만이어야 합니다.",
|
||||
"settings_latitude": "위도",
|
||||
"settings_longitude": "경도",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "GPS 업데이트 시 제로 홉 광고 자동 전송",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "GPS 위치가 변경되면 제로 홉 광고를 전송합니다(광고에 위치 포함 필요).",
|
||||
"settings_contactSettings": "연락처 설정",
|
||||
"settings_contactSettingsSubtitle": "연락처 추가 방식 설정",
|
||||
"settings_privacyMode": "개인 정보 보호 모드",
|
||||
|
||||
@@ -1030,6 +1030,18 @@ abstract class AppLocalizations {
|
||||
/// **'Include location in advert.'**
|
||||
String get settings_advertLocationSubtitle;
|
||||
|
||||
/// No description provided for @settings_autoZeroHopAdvertOnGpsUpdate.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Auto Zero-Hop Advert On GPS Update'**
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate;
|
||||
|
||||
/// No description provided for @settings_autoZeroHopAdvertOnGpsUpdateSubtitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'When GPS location changes, send a zero-hop advert (requires Advert Location).'**
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle;
|
||||
|
||||
/// No description provided for @settings_multiAck.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -506,6 +506,14 @@ class AppLocalizationsBg extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Включи местоположение в обявата';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Автоматична zero-hop обява при GPS обновяване';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Когато GPS местоположението се промени, изпрати zero-hop обява (изисква местоположение в обявата).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Множество ACK';
|
||||
|
||||
|
||||
@@ -506,6 +506,14 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Standort in die Ankündigung einschließen.';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatische Zero-Hop-Ankündigung bei GPS-Update';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Wenn sich der GPS-Standort ändert, eine Zero-Hop-Ankündigung senden (erfordert Standort in der Ankündigung).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Mehrfach-ACKs';
|
||||
|
||||
|
||||
@@ -496,6 +496,14 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => 'Include location in advert.';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Auto Zero-Hop Advert On GPS Update';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'When GPS location changes, send a zero-hop advert (requires Advert Location).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Multi-ACKs';
|
||||
|
||||
|
||||
@@ -503,6 +503,14 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => 'Incluir ubicación en anuncio';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Anuncio de cero saltos automático al actualizar GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Cuando cambie la ubicación GPS, enviar un anuncio de cero saltos (requiere ubicación en anuncio).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Múltiples respuestas de confirmación';
|
||||
|
||||
|
||||
@@ -507,6 +507,14 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Inclure la localisation dans l\'annonce';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Annonce zéro saut automatique lors de la mise à jour GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Lorsque la position GPS change, envoyer une annonce zéro saut (nécessite la position dans l\'annonce).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Plusieurs accusés de réception';
|
||||
|
||||
|
||||
@@ -502,6 +502,14 @@ class AppLocalizationsHu extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'A hirdetésben szerepeljen a helyszín.';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatikus zero-hop hirdetés GPS-frissítéskor';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Ha a GPS-helyzet megváltozik, küldjön zero-hop hirdetést (a hirdetésben helymegadás szükséges).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Multi-ACK';
|
||||
|
||||
|
||||
@@ -507,6 +507,14 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Includi la posizione nell\'annuncio';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Annuncio zero-hop automatico all\'aggiornamento GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Quando la posizione GPS cambia, invia un annuncio zero-hop (richiede la posizione nell\'annuncio).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'ACK multipli';
|
||||
|
||||
|
||||
@@ -482,6 +482,13 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => '広告に場所を記載してください。';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate => 'GPS更新時にゼロホップ広告を自動送信';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'GPS位置が変化したときにゼロホップ広告を送信します(広告への位置情報の含有が必要)。';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'マルチ ACK';
|
||||
|
||||
|
||||
@@ -483,6 +483,14 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => '광고에 위치 정보를 포함하세요.';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'GPS 업데이트 시 제로 홉 광고 자동 전송';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'GPS 위치가 변경되면 제로 홉 광고를 전송합니다(광고에 위치 포함 필요).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => '다중 ACK';
|
||||
|
||||
|
||||
@@ -501,6 +501,14 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Locatie opnemen in advertentie';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatische zero-hop-advertentie bij GPS-update';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Wanneer de GPS-locatie verandert, een zero-hop-advertentie verzenden (vereist locatie in advertentie).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Meerdere bevestigingen';
|
||||
|
||||
|
||||
@@ -508,6 +508,14 @@ class AppLocalizationsPl extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Uwzględnij lokalizację w ogłoszeniu';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatyczne ogłoszenie zero-hop przy aktualizacji GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Gdy lokalizacja GPS się zmieni, wyślij ogłoszenie zero-hop (wymaga lokalizacji w ogłoszeniu).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Wielokrotne potwierdzenia odbioru';
|
||||
|
||||
|
||||
@@ -505,6 +505,14 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Incluir localização no anúncio';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Anúncio zero-hop automático na atualização do GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Quando a localização GPS mudar, enviar um anúncio zero-hop (requer localização no anúncio).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Multi-ACKs';
|
||||
|
||||
|
||||
@@ -505,6 +505,14 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Включить местоположение в объявление';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Авто-объявление без хопов при обновлении GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Когда GPS-местоположение меняется, отправлять объявление без хопов (требуется геопозиция в объявлении).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Несколько подтверждений';
|
||||
|
||||
|
||||
@@ -499,6 +499,14 @@ class AppLocalizationsSk extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => 'Zahrnúť polohu do inzerátu';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatický zero-hop inzerát pri aktualizácii GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Keď sa GPS poloha zmení, odoslať zero-hop inzerát (vyžaduje polohu v inzeráte).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Viaceré ACK';
|
||||
|
||||
|
||||
@@ -500,6 +500,14 @@ class AppLocalizationsSl extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => 'Vključi lokacijo v oglas.';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Samodejni zero-hop oglas ob posodobitvi GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Ko se GPS lokacija spremeni, pošlji zero-hop oglas (zahteva lokacijo v oglasu).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Več potrdil';
|
||||
|
||||
|
||||
@@ -497,6 +497,14 @@ class AppLocalizationsSv extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => 'Inkludera plats i annonsen';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Automatisk zero-hop-annons vid GPS-uppdatering';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'När GPS-positionen ändras, skicka en zero-hop-annons (kräver plats i annonsen).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Flera bekräftelser';
|
||||
|
||||
|
||||
@@ -501,6 +501,14 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
String get settings_advertLocationSubtitle =>
|
||||
'Включити геопозицію в оголошення';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate =>
|
||||
'Автооголошення без хопів при оновленні GPS';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'Коли GPS-локація змінюється, надсилати оголошення без хопів (потрібна геопозиція в оголошенні).';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => 'Багато підтверджень';
|
||||
|
||||
|
||||
@@ -476,6 +476,13 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get settings_advertLocationSubtitle => '在广告中包含位置';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdate => 'GPS 更新时自动发送零跳广告';
|
||||
|
||||
@override
|
||||
String get settings_autoZeroHopAdvertOnGpsUpdateSubtitle =>
|
||||
'当 GPS 位置变化时,发送零跳广告(需要在广告中包含位置)。';
|
||||
|
||||
@override
|
||||
String get settings_multiAck => '多重ACK';
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Ongeldige breedtegraad of lengtegraad.",
|
||||
"settings_latitude": "Breedtegraad",
|
||||
"settings_longitude": "Lengtegraad",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatische zero-hop-advertentie bij GPS-update",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Wanneer de GPS-locatie verandert, een zero-hop-advertentie verzenden (vereist locatie in advertentie).",
|
||||
"settings_privacyMode": "Privacy-modus",
|
||||
"settings_privacyModeSubtitle": "Naam/locatie verbergen in advertenties",
|
||||
"settings_privacyModeToggle": "Schakel privacy modus in om je naam en locatie in advertenties te verbergen.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Nieprawidłowa szerokość geograficzna lub długość geograficzna.",
|
||||
"settings_latitude": "Szerokość",
|
||||
"settings_longitude": "Długość",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatyczne ogłoszenie zero-hop przy aktualizacji GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Gdy lokalizacja GPS się zmieni, wyślij ogłoszenie zero-hop (wymaga lokalizacji w ogłoszeniu).",
|
||||
"settings_privacyMode": "Tryb prywatności",
|
||||
"settings_privacyModeSubtitle": "Ukryj imię/lokalizację w rozgłoszeniach",
|
||||
"settings_privacyModeToggle": "Włącz tryb prywatności, aby ukryć swoje imię i lokalizację w rozgłoszeniach.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Latitude ou longitude inválidos.",
|
||||
"settings_latitude": "Latitude",
|
||||
"settings_longitude": "Longitude",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Anúncio zero-hop automático na atualização do GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Quando a localização GPS mudar, enviar um anúncio zero-hop (requer localização no anúncio).",
|
||||
"settings_privacyMode": "Modo de Privacidade",
|
||||
"settings_privacyModeSubtitle": "Esconder nome/localização em anúncios",
|
||||
"settings_privacyModeToggle": "Ative o modo de privacidade para ocultar seu nome e localização em anúncios.",
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
"settings_locationIntervalInvalid": "Интервал должен составлять не менее 60 секунд и не более 86400 секунд.",
|
||||
"settings_latitude": "Широта",
|
||||
"settings_longitude": "Долгота",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Авто-объявление без хопов при обновлении GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Когда GPS-местоположение меняется, отправлять объявление без хопов (требуется геопозиция в объявлении).",
|
||||
"settings_privacyMode": "Режим конфиденциальности",
|
||||
"settings_privacyModeSubtitle": "Скрыть имя/позицию в анонсировании",
|
||||
"settings_privacyModeToggle": "Включите режим конфиденциальности, чтобы скрыть свое имя и местоположение в анонсировании.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Neplatná šírka alebo dĺžka.",
|
||||
"settings_latitude": "Súradnica",
|
||||
"settings_longitude": "Dĺžka",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatický zero-hop inzerát pri aktualizácii GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Keď sa GPS poloha zmení, odoslať zero-hop inzerát (vyžaduje polohu v inzeráte).",
|
||||
"settings_privacyMode": "Režim ochrany súkromia",
|
||||
"settings_privacyModeSubtitle": "Skryť meno/poloha v reklamách",
|
||||
"settings_privacyModeToggle": "Prepínač súkromného režimu skryje vaše meno a polohu v reklamách.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Neveljavna zemeljska širina ali dolžina.",
|
||||
"settings_latitude": "Širina",
|
||||
"settings_longitude": "Dolžina",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Samodejni zero-hop oglas ob posodobitvi GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Ko se GPS lokacija spremeni, pošlji zero-hop oglas (zahteva lokacijo v oglasu).",
|
||||
"settings_privacyMode": "Zasebnost",
|
||||
"settings_privacyModeSubtitle": "Skrita imena/lokacije v oglasih",
|
||||
"settings_privacyModeToggle": "Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.",
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
"settings_locationInvalid": "Ogiltig latitud eller longitud.",
|
||||
"settings_latitude": "Latitud",
|
||||
"settings_longitude": "Längdgrad",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Automatisk zero-hop-annons vid GPS-uppdatering",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "När GPS-positionen ändras, skicka en zero-hop-annons (kräver plats i annonsen).",
|
||||
"settings_privacyMode": "Privatläge",
|
||||
"settings_privacyModeSubtitle": "Dölj namn/plats i annonser",
|
||||
"settings_privacyModeToggle": "Aktivera privatläge för att dölja ditt namn och din plats i annonser.",
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
"settings_locationInvalid": "Некоректна широта або довгота.",
|
||||
"settings_latitude": "Широта",
|
||||
"settings_longitude": "Довгота",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "Автооголошення без хопів при оновленні GPS",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "Коли GPS-локація змінюється, надсилати оголошення без хопів (потрібна геопозиція в оголошенні).",
|
||||
"settings_privacyMode": "Режим приватності",
|
||||
"settings_privacyModeSubtitle": "Приховати ім'я/геопозицію в оголошеннях",
|
||||
"settings_privacyModeToggle": "Увімкніть режим приватності, щоб приховати своє ім'я та геопозицію в оголошеннях.",
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
"settings_locationIntervalInvalid": "间隔时间必须至少为 60 秒,但不超过 86400 秒。",
|
||||
"settings_latitude": "纬度",
|
||||
"settings_longitude": "经度",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdate": "GPS 更新时自动发送零跳广告",
|
||||
"settings_autoZeroHopAdvertOnGpsUpdateSubtitle": "当 GPS 位置变化时,发送零跳广告(需要在广告中包含位置)。",
|
||||
"settings_privacyMode": "隐私模式",
|
||||
"settings_privacyModeSubtitle": "在广告中隐藏姓名/位置",
|
||||
"settings_privacyModeToggle": "切换隐私模式以在广告中隐藏姓名和位置,保护个人信息。",
|
||||
|
||||
@@ -95,6 +95,8 @@ class AppSettings {
|
||||
final bool notifyOnNewMessage;
|
||||
final bool notifyOnNewChannelMessage;
|
||||
final bool notifyOnNewAdvert;
|
||||
final bool autoSendZeroHopAdvertOnGpsUpdate;
|
||||
final int gpsIntervalSeconds;
|
||||
final bool autoRouteRotationEnabled;
|
||||
final double maxRouteWeight;
|
||||
final double initialRouteWeight;
|
||||
@@ -149,6 +151,8 @@ class AppSettings {
|
||||
this.notifyOnNewMessage = true,
|
||||
this.notifyOnNewChannelMessage = true,
|
||||
this.notifyOnNewAdvert = true,
|
||||
this.autoSendZeroHopAdvertOnGpsUpdate = false,
|
||||
this.gpsIntervalSeconds = 900,
|
||||
this.autoRouteRotationEnabled = true,
|
||||
this.maxRouteWeight = 5.0,
|
||||
this.initialRouteWeight = 3.0,
|
||||
@@ -210,6 +214,9 @@ class AppSettings {
|
||||
'notify_on_new_message': notifyOnNewMessage,
|
||||
'notify_on_new_channel_message': notifyOnNewChannelMessage,
|
||||
'notify_on_new_advert': notifyOnNewAdvert,
|
||||
'auto_send_zero_hop_advert_on_gps_update':
|
||||
autoSendZeroHopAdvertOnGpsUpdate,
|
||||
'gps_interval_seconds': gpsIntervalSeconds,
|
||||
'auto_route_rotation_enabled': autoRouteRotationEnabled,
|
||||
'max_route_weight': maxRouteWeight,
|
||||
'initial_route_weight': initialRouteWeight,
|
||||
@@ -275,6 +282,10 @@ class AppSettings {
|
||||
notifyOnNewChannelMessage:
|
||||
json['notify_on_new_channel_message'] as bool? ?? true,
|
||||
notifyOnNewAdvert: json['notify_on_new_advert'] as bool? ?? true,
|
||||
autoSendZeroHopAdvertOnGpsUpdate:
|
||||
json['auto_send_zero_hop_advert_on_gps_update'] as bool? ?? false,
|
||||
gpsIntervalSeconds:
|
||||
(json['gps_interval_seconds'] as num?)?.toInt() ?? 900,
|
||||
autoRouteRotationEnabled:
|
||||
json['auto_route_rotation_enabled'] as bool? ?? true,
|
||||
maxRouteWeight: (json['max_route_weight'] as num?)?.toDouble() ?? 5.0,
|
||||
@@ -383,6 +394,8 @@ class AppSettings {
|
||||
bool? notifyOnNewMessage,
|
||||
bool? notifyOnNewChannelMessage,
|
||||
bool? notifyOnNewAdvert,
|
||||
bool? autoSendZeroHopAdvertOnGpsUpdate,
|
||||
int? gpsIntervalSeconds,
|
||||
bool? autoRouteRotationEnabled,
|
||||
double? maxRouteWeight,
|
||||
double? initialRouteWeight,
|
||||
@@ -433,6 +446,10 @@ class AppSettings {
|
||||
notifyOnNewChannelMessage:
|
||||
notifyOnNewChannelMessage ?? this.notifyOnNewChannelMessage,
|
||||
notifyOnNewAdvert: notifyOnNewAdvert ?? this.notifyOnNewAdvert,
|
||||
autoSendZeroHopAdvertOnGpsUpdate:
|
||||
autoSendZeroHopAdvertOnGpsUpdate ??
|
||||
this.autoSendZeroHopAdvertOnGpsUpdate,
|
||||
gpsIntervalSeconds: gpsIntervalSeconds ?? this.gpsIntervalSeconds,
|
||||
autoRouteRotationEnabled:
|
||||
autoRouteRotationEnabled ?? this.autoRouteRotationEnabled,
|
||||
maxRouteWeight: maxRouteWeight ?? this.maxRouteWeight,
|
||||
|
||||
@@ -9,6 +9,7 @@ import '../connector/meshcore_connector.dart';
|
||||
import '../connector/meshcore_protocol.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../models/radio_settings.dart';
|
||||
import '../services/app_settings_service.dart';
|
||||
import '../services/app_debug_log_service.dart';
|
||||
import '../theme/mesh_theme.dart';
|
||||
import '../widgets/app_bar.dart';
|
||||
@@ -761,6 +762,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
|
||||
void _editLocation(BuildContext context, MeshCoreConnector connector) {
|
||||
final l10n = context.l10n;
|
||||
final settingsService = context.read<AppSettingsService>();
|
||||
final latController = TextEditingController();
|
||||
final lonController = TextEditingController();
|
||||
final intervalController = TextEditingController();
|
||||
@@ -772,9 +774,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
final bool hasGPS = customVars.containsKey("gps");
|
||||
bool isGPSEnabled = customVars["gps"] == "1";
|
||||
|
||||
// Read current interval or default to 900 (15 minutes)
|
||||
final currentInterval =
|
||||
int.tryParse(customVars["gps_interval"] ?? "") ?? 900;
|
||||
final currentInterval = settingsService.resolvedGpsIntervalSeconds(
|
||||
customVars,
|
||||
);
|
||||
intervalController.text = currentInterval.toString();
|
||||
|
||||
String? intervalError;
|
||||
@@ -872,7 +874,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
Navigator.pop(context);
|
||||
|
||||
if (interval != null) {
|
||||
await connector.setCustomVar("gps_interval:$interval");
|
||||
await settingsService.setGpsIntervalSeconds(
|
||||
interval,
|
||||
writeToDevice: (value) =>
|
||||
connector.setCustomVar("gps_interval:$value"),
|
||||
);
|
||||
await connector.refreshDeviceInfo();
|
||||
if (!context.mounted) return;
|
||||
showDismissibleSnackBar(
|
||||
@@ -1172,12 +1178,15 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
|
||||
void _privacySettings(BuildContext context, MeshCoreConnector connector) {
|
||||
final l10n = context.l10n;
|
||||
final settingsService = context.read<AppSettingsService>();
|
||||
|
||||
int telemetryMode = connector.telemetryModeBase;
|
||||
int telemetryLocMode = connector.telemetryModeLoc;
|
||||
int telemetryEnvMode = connector.telemetryModeEnv;
|
||||
bool advertLocPolicy = connector.advertLocationPolicy == 0 ? false : true;
|
||||
int multiAcks = connector.multiAcks;
|
||||
bool autoZeroHopAdvertOnGpsUpdate =
|
||||
settingsService.settings.autoSendZeroHopAdvertOnGpsUpdate;
|
||||
|
||||
final telemModeBase = [
|
||||
DropdownMenuItem(value: teleModeDeny, child: Text(l10n.settings_denyAll)),
|
||||
@@ -1212,6 +1221,20 @@ void _privacySettings(BuildContext context, MeshCoreConnector connector) {
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FeatureToggleRow(
|
||||
title: l10n.settings_autoZeroHopAdvertOnGpsUpdate,
|
||||
subtitle: l10n.settings_autoZeroHopAdvertOnGpsUpdateSubtitle,
|
||||
value: autoZeroHopAdvertOnGpsUpdate,
|
||||
enabled: advertLocPolicy,
|
||||
onChanged: advertLocPolicy
|
||||
? (value) {
|
||||
setDialogState(
|
||||
() => autoZeroHopAdvertOnGpsUpdate = value,
|
||||
);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SwitchListTile(
|
||||
title: Text(l10n.settings_multiAck),
|
||||
value: multiAcks == 1,
|
||||
@@ -1280,6 +1303,9 @@ void _privacySettings(BuildContext context, MeshCoreConnector connector) {
|
||||
advertLocPolicy ? 1 : 0,
|
||||
multiAcks,
|
||||
);
|
||||
await settingsService.setAutoSendZeroHopAdvertOnGpsUpdate(
|
||||
autoZeroHopAdvertOnGpsUpdate,
|
||||
);
|
||||
await connector.refreshDeviceInfo();
|
||||
if (!context.mounted) return;
|
||||
showDismissibleSnackBar(
|
||||
|
||||
@@ -13,6 +13,14 @@ class AppSettingsService extends ChangeNotifier {
|
||||
|
||||
AppSettings get settings => _settings;
|
||||
|
||||
int resolvedGpsIntervalSeconds(Map<String, String>? deviceCustomVars) {
|
||||
final deviceValue = int.tryParse(deviceCustomVars?['gps_interval'] ?? '');
|
||||
if (deviceValue != null && deviceValue >= 0) {
|
||||
return deviceValue;
|
||||
}
|
||||
return _settings.gpsIntervalSeconds;
|
||||
}
|
||||
|
||||
String batteryChemistryForDevice(String deviceId) {
|
||||
final stored = _settings.batteryChemistryByDeviceId[deviceId];
|
||||
if (stored == 'liion') return 'nmc';
|
||||
@@ -128,6 +136,28 @@ class AppSettingsService extends ChangeNotifier {
|
||||
await updateSettings(_settings.copyWith(notifyOnNewAdvert: value));
|
||||
}
|
||||
|
||||
Future<void> setAutoSendZeroHopAdvertOnGpsUpdate(bool value) async {
|
||||
await updateSettings(
|
||||
_settings.copyWith(autoSendZeroHopAdvertOnGpsUpdate: value),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setGpsIntervalSeconds(
|
||||
int value, {
|
||||
Future<void> Function(int value)? writeToDevice,
|
||||
}) async {
|
||||
await updateSettings(_settings.copyWith(gpsIntervalSeconds: value));
|
||||
if (writeToDevice == null) return;
|
||||
try {
|
||||
await writeToDevice(value);
|
||||
} catch (e) {
|
||||
appLogger.warn(
|
||||
'Failed to write GPS interval to device: $e',
|
||||
tag: 'AppSettings',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setAutoRouteRotationEnabled(bool value) async {
|
||||
await updateSettings(_settings.copyWith(autoRouteRotationEnabled: value));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ class FeatureToggleRow extends StatefulWidget {
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final bool value;
|
||||
final bool enabled;
|
||||
final bool hasRefreshing;
|
||||
final bool isRefreshing;
|
||||
final ValueChanged<bool>? onChanged;
|
||||
@@ -15,6 +16,7 @@ class FeatureToggleRow extends StatefulWidget {
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.value,
|
||||
this.enabled = true,
|
||||
this.hasRefreshing = false,
|
||||
this.isRefreshing = false,
|
||||
this.onChanged,
|
||||
@@ -31,6 +33,13 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final isEnabled = widget.enabled;
|
||||
final titleColor = isEnabled
|
||||
? scheme.onSurface
|
||||
: scheme.onSurfaceVariant.withValues(alpha: 0.7);
|
||||
final subtitleColor = isEnabled
|
||||
? scheme.onSurfaceVariant
|
||||
: scheme.onSurfaceVariant.withValues(alpha: 0.55);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
@@ -44,14 +53,13 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
widget.title,
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: titleColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
widget.subtitle,
|
||||
style: textTheme.bodySmall?.copyWith(
|
||||
color: scheme.onSurfaceVariant,
|
||||
),
|
||||
style: textTheme.bodySmall?.copyWith(color: subtitleColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -60,7 +68,18 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Switch(value: widget.value, onChanged: widget.onChanged),
|
||||
Switch(
|
||||
value: widget.value,
|
||||
onChanged: isEnabled ? widget.onChanged : null,
|
||||
thumbColor: !isEnabled
|
||||
? WidgetStatePropertyAll<Color?>(scheme.onSurfaceVariant)
|
||||
: null,
|
||||
trackColor: !isEnabled
|
||||
? WidgetStatePropertyAll<Color?>(
|
||||
scheme.onSurfaceVariant.withValues(alpha: 0.35),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (widget.hasRefreshing) ...[
|
||||
const SizedBox(width: 4),
|
||||
widget.isRefreshing
|
||||
@@ -74,7 +93,7 @@ class _FeatureToggleRow extends State<FeatureToggleRow> {
|
||||
)
|
||||
: IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 18),
|
||||
onPressed: widget.onRefresh,
|
||||
onPressed: isEnabled ? widget.onRefresh : null,
|
||||
tooltip: widget.refreshTooltip,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
|
||||
@@ -5,6 +5,9 @@ import 'package:meshcore_open/models/contact.dart';
|
||||
import 'package:meshcore_open/models/path_history.dart';
|
||||
import 'package:meshcore_open/models/app_settings.dart';
|
||||
import 'package:meshcore_open/connector/meshcore_protocol.dart';
|
||||
import 'package:meshcore_open/services/app_settings_service.dart';
|
||||
import 'package:meshcore_open/storage/prefs_manager.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
// Builds a valid contact frame with the given pathLen and optional overrides.
|
||||
// Frame layout: [respCode(1)][pubKey(32)][type(1)][flags(1)][pathLen(1)][path(64)][name(32)][timestamp(4)][lat(4)][lon(4)]
|
||||
@@ -38,6 +41,14 @@ Uint8List _buildContactFrame({
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUp(() async {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
PrefsManager.reset();
|
||||
await PrefsManager.initialize();
|
||||
});
|
||||
|
||||
group('Contact.fromFrame — pathLen mapping', () {
|
||||
test('pathLen == 0 → pathLength == 0 (direct, NOT flood)', () {
|
||||
final frame = _buildContactFrame(pathLen: 0);
|
||||
@@ -358,4 +369,44 @@ void main() {
|
||||
expect(updated.maxRouteWeight, equals(settings.maxRouteWeight));
|
||||
});
|
||||
});
|
||||
|
||||
group('AppSettingsService — gps interval fallback', () {
|
||||
test('resolvedGpsIntervalSeconds prefers device custom var', () {
|
||||
final service = AppSettingsService();
|
||||
|
||||
expect(
|
||||
service.resolvedGpsIntervalSeconds(const {'gps_interval': '120'}),
|
||||
equals(120),
|
||||
);
|
||||
});
|
||||
|
||||
test('resolvedGpsIntervalSeconds falls back to stored value', () async {
|
||||
final service = AppSettingsService();
|
||||
await service.updateSettings(AppSettings(gpsIntervalSeconds: 900));
|
||||
|
||||
expect(service.resolvedGpsIntervalSeconds(null), equals(900));
|
||||
expect(
|
||||
service.resolvedGpsIntervalSeconds(const {'gps_interval': 'bad'}),
|
||||
equals(900),
|
||||
);
|
||||
});
|
||||
|
||||
test('resolvedGpsIntervalSeconds keeps an explicit device zero', () async {
|
||||
final service = AppSettingsService();
|
||||
await service.updateSettings(AppSettings(gpsIntervalSeconds: 900));
|
||||
|
||||
expect(
|
||||
service.resolvedGpsIntervalSeconds(const {'gps_interval': '0'}),
|
||||
equals(0),
|
||||
);
|
||||
});
|
||||
|
||||
test('toJson/fromJson preserves gpsIntervalSeconds', () {
|
||||
final settings = AppSettings(gpsIntervalSeconds: 321);
|
||||
|
||||
final restored = AppSettings.fromJson(settings.toJson());
|
||||
|
||||
expect(restored.gpsIntervalSeconds, equals(321));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user