From 98fc2d6e0ab68ae3c30a0f2da08a878c348a3b16 Mon Sep 17 00:00:00 2001 From: Winston Lowe Date: Mon, 19 Jan 2026 16:56:32 -0800 Subject: [PATCH] Updated gps setting to follow state of companion. --- lib/l10n/app_bg.arb | 8 +- lib/l10n/app_de.arb | 6 +- lib/l10n/app_en.arb | 4 +- lib/l10n/app_es.arb | 4 +- lib/l10n/app_fr.arb | 6 +- lib/l10n/app_it.arb | 4 +- lib/l10n/app_localizations.dart | 4 +- lib/l10n/app_localizations_en.dart | 4 +- lib/l10n/app_nl.arb | 4 +- lib/l10n/app_pl.arb | 4 +- lib/l10n/app_pt.arb | 6 +- lib/l10n/app_sk.arb | 4 +- lib/l10n/app_sl.arb | 6 +- lib/l10n/app_sv.arb | 4 +- lib/l10n/app_zh.arb | 4 +- lib/screens/settings_screen.dart | 156 +++++++++++++++-------------- lib/widgets/elements_ui.dart | 59 +++++++++++ 17 files changed, 174 insertions(+), 113 deletions(-) create mode 100644 lib/widgets/elements_ui.dart diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index effbd6c2..7a3216d4 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "Ще излезе скоро", "channels_enterHashtag": "Въведете хаштаг", "channels_hashtagHint": "напр. #отбор", - "settings_locationIntervalSec": "Интервал (Секунди)", - "settings_locationGPSEnableSubtitle": "Активирайте GPS, за автоматично изпращане на данни за местоположението (ако е поддържано).", - "settings_locationIntervalInvalid": "Интервалът трябва да бъде поне 60 секунди и по-малко от 86400 секунди.", - "settings_locationGPSEnable": "Активиране на GPS" + "settings_locationIntervalSec": "Интервал за GPS (Секунди)", + "settings_locationGPSEnable": "Активиране на GPS", + "settings_locationGPSEnableSubtitle": "Активирайте автоматичното актуализиране на местоположението чрез GPS.", + "settings_locationIntervalInvalid": "Интервалът трябва да бъде поне 60 секунди и по-малко от 86400 секунди." } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index dead738f..a208393e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Gib Hashtag ein", "channels_hashtagHint": "z.B. #team", "settings_locationGPSEnable": "GPS aktivieren", - "settings_locationGPSEnableSubtitle": "Aktivieren Sie GPS, um Standortdaten automatisch zu senden (falls unterstützt).", - "settings_locationIntervalSec": "Zeitintervall (Sekunden)", - "settings_locationIntervalInvalid": "Der Zeitraum muss mindestens 60 Sekunden betragen und weniger als 86400 Sekunden sein." + "settings_locationGPSEnableSubtitle": "Aktivieren Sie die automatische Aktualisierung der Standortdaten per GPS.", + "settings_locationIntervalInvalid": "Der Zeitraum muss mindestens 60 Sekunden betragen und weniger als 86400 Sekunden sein.", + "settings_locationIntervalSec": "Zeitintervall für GPS (Sekunden)" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9b2547cb..988a8764 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -87,8 +87,8 @@ "settings_locationBothRequired": "Enter both latitude and longitude.", "settings_locationInvalid": "Invalid latitude or longitude.", "settings_locationGPSEnable": "GPS Enable", - "settings_locationGPSEnableSubtitle": "Enable GPS to automatically send location data (if supported)", - "settings_locationIntervalSec": "Interval (Seconds)", + "settings_locationGPSEnableSubtitle": "Enables GPS to automatically update location.", + "settings_locationIntervalSec": "Interval for GPS (Seconds)", "settings_locationIntervalInvalid": "Interval must be at least 60 seconds, and less than 86400 seconds.", "settings_locationUpdated": "GPS settings updated.", "settings_latitude": "Latitude", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index bf90fe4e..3c4453a3 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "Próximamente", "channels_enterHashtag": "Introducir hashtag", "channels_hashtagHint": "ej. #equipo", - "settings_locationGPSEnableSubtitle": "Habilitar GPS para enviar automáticamente datos de ubicación (si está disponible).", "settings_locationGPSEnable": "Habilitar GPS", - "settings_locationIntervalSec": "Intervalo (Segundos)", + "settings_locationGPSEnableSubtitle": "Habilita la actualización automática de la ubicación mediante GPS.", + "settings_locationIntervalSec": "Intervalo para GPS (Segundos)", "settings_locationIntervalInvalid": "El intervalo debe ser de al menos 60 segundos y menor que 86400 segundos." } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 82d73d7a..13cde8ed 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "Bientôt disponible", "channels_enterHashtag": "Entrez le hashtag", "channels_hashtagHint": "ex. #équipe", + "settings_locationGPSEnableSubtitle": "Activer la mise à jour automatique de la position grâce au GPS.", + "settings_locationIntervalInvalid": "L'intervalle doit être d’au moins 60 secondes et inférieur à 86400 secondes.", "settings_locationGPSEnable": "Activer le GPS", - "settings_locationGPSEnableSubtitle": "Activer le GPS pour envoyer automatiquement les données de localisation (si pris en charge).", - "settings_locationIntervalSec": "Intervalle (Secondes)", - "settings_locationIntervalInvalid": "L'intervalle doit être d'au moins 60 secondes et inférieur à 86400 secondes." + "settings_locationIntervalSec": "Intervalle GPS (Secondes)" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index f9828e54..d447c505 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "Arriverà presto", "channels_enterHashtag": "Inserisci hashtag", "channels_hashtagHint": "es. #team", - "settings_locationGPSEnableSubtitle": "Abilita il GPS per inviare automaticamente i dati di posizione (se supportato).", "settings_locationGPSEnable": "Abilita GPS", - "settings_locationIntervalSec": "Intervallo (Secondi)", + "settings_locationGPSEnableSubtitle": "Abilita l'aggiornamento automatico della posizione tramite GPS.", + "settings_locationIntervalSec": "Intervallo GPS (Secondi)", "settings_locationIntervalInvalid": "L'intervallo deve essere di almeno 60 secondi e inferiore a 86400 secondi." } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index cfe77e2c..2916b914 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -489,13 +489,13 @@ abstract class AppLocalizations { /// No description provided for @settings_locationGPSEnableSubtitle. /// /// In en, this message translates to: - /// **'Enable GPS to automatically send location data (if supported)'** + /// **'Enables GPS to automatically send location data (if supported)'** String get settings_locationGPSEnableSubtitle; /// No description provided for @settings_locationIntervalSec. /// /// In en, this message translates to: - /// **'Interval (Seconds)'** + /// **'Interval for GPS (Seconds)'** String get settings_locationIntervalSec; /// No description provided for @settings_locationIntervalInvalid. diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index e7ea0cf2..a7e88cbd 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -204,10 +204,10 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_locationGPSEnableSubtitle => - 'Enable GPS to automatically send location data (if supported)'; + 'Enables GPS to automatically send location data (if supported)'; @override - String get settings_locationIntervalSec => 'Interval (Seconds)'; + String get settings_locationIntervalSec => 'Interval for GPS (Seconds)'; @override String get settings_locationIntervalInvalid => diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index a0ddfe87..5f2e2f70 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Voer hashtag in", "channels_hashtagHint": "bijv. #team", "settings_locationGPSEnable": "GPS inschakelen", - "settings_locationGPSEnableSubtitle": "Zijze GPS inschakelen om locatiegegevens automatisch te verzenden (indien ondersteund).", + "settings_locationIntervalSec": "Interval voor GPS (Seconden)", "settings_locationIntervalInvalid": "De intervallen moeten minstens 60 seconden zijn en minder dan 86400 seconden.", - "settings_locationIntervalSec": "Interval (Seconden)" + "settings_locationGPSEnableSubtitle": "Activeer automatisch locatieupdates via GPS." } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 23938a5a..15ce2b85 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Wprowadź hashtag", "channels_hashtagHint": "np. #zespół", "settings_locationGPSEnable": "Włącz GPS", - "settings_locationGPSEnableSubtitle": "Włącz GPS, aby automatycznie wysyłać dane o lokalizacji (jeśli jest obsługiwane).", - "settings_locationIntervalSec": "Interwał (Sekundy)", + "settings_locationIntervalSec": "Interwał dla GPS (Sekundy)", + "settings_locationGPSEnableSubtitle": "Włącza automatyczne aktualizowanie pozycji za pomocą GPS.", "settings_locationIntervalInvalid": "Interwał musi wynosić co najmniej 60 sekund i mniej niż 86400 sekund." } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index b49f2861..0b09582e 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Insira hashtag", "channels_hashtagHint": "ex. #equipe", "settings_locationGPSEnable": "Ativar GPS", - "settings_locationGPSEnableSubtitle": "Habilite o GPS para enviar dados de localização automaticamente (se suportado).", - "settings_locationIntervalSec": "Intervalo (Segundos)", - "settings_locationIntervalInvalid": "O intervalo deve ser de pelo menos 60 segundos e inferior a 86400 segundos." + "settings_locationGPSEnableSubtitle": "Habilita a atualização automática da localização via GPS.", + "settings_locationIntervalInvalid": "O intervalo deve ser de pelo menos 60 segundos e inferior a 86400 segundos.", + "settings_locationIntervalSec": "Intervalo para GPS (Segundos)" } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index aa242c37..06de0240 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Zadajte hashtag", "channels_hashtagHint": "napr. #tím", "settings_locationGPSEnable": "Aktivovať GPS", - "settings_locationGPSEnableSubtitle": "Zapnite GPS na automatické posielanie dát o polohe (ak je podporované).", - "settings_locationIntervalSec": "Interval (Sekundy)", + "settings_locationGPSEnableSubtitle": "Povolí automatické aktualizovanie polohy pomocou GPS.", + "settings_locationIntervalSec": "Interval pre GPS (Sekundy)", "settings_locationIntervalInvalid": "Interval musí byť aspoň 60 sekúnd a menej ako 86400 sekúnd." } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index e078d409..05e99b7f 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1350,7 +1350,7 @@ "channels_enterHashtag": "Vnesite hashtag", "channels_hashtagHint": "npr. #ekipa", "settings_locationGPSEnable": "Omogoči GPS", - "settings_locationGPSEnableSubtitle": "Omogoči GPS za samodejno pošiljanje podatkov o lokaciji (če je podprto).", - "settings_locationIntervalSec": "Interval (Sekunde)", - "settings_locationIntervalInvalid": "Intervallo mora biti vsaj 60 sekund in manj kot 86400 sekund." + "settings_locationGPSEnableSubtitle": "Omogoči samodejno posodabljanje lokacije z GPS-jem.", + "settings_locationIntervalInvalid": "Intervallo mora biti vsaj 60 sekund in manj kot 86400 sekund.", + "settings_locationIntervalSec": "Interval za GPS (Sekunde)" } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 2f580cbd..deef6c63 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "Kommer snart", "channels_enterHashtag": "Ange hashtag", "channels_hashtagHint": "t.ex. #team", + "settings_locationGPSEnableSubtitle": "Aktiverar automatiska uppdateringar av platsen med hjälp av GPS.", "settings_locationGPSEnable": "Aktivera GPS", - "settings_locationIntervalSec": "Tidsintervall (Sekunder)", - "settings_locationGPSEnableSubtitle": "Aktivera GPS för att automatiskt skicka platsdata (om det stöds).", + "settings_locationIntervalSec": "Interval för GPS (Sekunder)", "settings_locationIntervalInvalid": "Intervalet måste vara minst 60 sekunder och mindre än 86400 sekunder." } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index fa9e64d4..d0f4dce1 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1349,8 +1349,8 @@ "channels_scanQrCodeComingSoon": "即将到来", "channels_enterHashtag": "输入标签", "channels_hashtagHint": "例如 #团队", - "settings_locationGPSEnableSubtitle": "启用GPS自动发送位置数据(如果支持)。", "settings_locationGPSEnable": "启用GPS", - "settings_locationIntervalSec": "时间间隔(秒)", + "settings_locationGPSEnableSubtitle": "启用GPS自动更新位置。", + "settings_locationIntervalSec": "GPS 间隔(秒)", "settings_locationIntervalInvalid": "时间间隔必须至少为60秒,且小于86400秒。" } diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index d925c30b..c4ce483b 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:meshcore_open/widgets/elements_ui.dart'; import 'package:provider/provider.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -435,7 +436,13 @@ class _SettingsScreenState extends State { intervalController.text = "900"; latController.text = connector.selfLatitude?.toStringAsFixed(6) ?? ''; lonController.text = connector.selfLongitude?.toStringAsFixed(6) ?? ''; - bool isGPSEnabled = false; + bool hasGPS = connector.currentCustomVars!.isNotEmpty + ? connector.currentCustomVars!.containsKey("gps") + : false; + + bool isGPSEnabled = hasGPS + ? connector.currentCustomVars!["gps"] == "1" + : false; showDialog( context: context, @@ -445,48 +452,30 @@ class _SettingsScreenState extends State { content: Column( mainAxisSize: MainAxisSize.min, children: [ - if (!isGPSEnabled) ...[ - TextField( - controller: latController, - decoration: InputDecoration( - labelText: l10n.settings_latitude, - border: const OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: true, - signed: true, - ), + TextField( + controller: latController, + decoration: InputDecoration( + labelText: l10n.settings_latitude, + border: const OutlineInputBorder(), ), - const SizedBox(height: 16), - TextField( - controller: lonController, - decoration: InputDecoration( - labelText: l10n.settings_longitude, - border: const OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: true, - signed: true, - ), - ), - ], - const SizedBox(height: 16), - CheckboxListTile( - value: isGPSEnabled, - enabled: true, - onChanged: (v) => - setDialogState(() => isGPSEnabled = v ?? false), - //controlAffinity: ListTileControlAffinity.leading, - title: Text( - l10n.settings_locationGPSEnable, - style: TextStyle(fontSize: 12), - ), - subtitle: Text( - l10n.settings_locationGPSEnableSubtitle, - style: TextStyle(fontSize: 10), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + signed: true, ), ), - if (isGPSEnabled) ...{ + const SizedBox(height: 16), + TextField( + controller: lonController, + decoration: InputDecoration( + labelText: l10n.settings_longitude, + border: const OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + signed: true, + ), + ), + if (hasGPS) ...[ const SizedBox(height: 16), TextField( controller: intervalController, @@ -499,7 +488,21 @@ class _SettingsScreenState extends State { signed: false, ), ), - }, + const SizedBox(height: 16), + FeatureToggleRow( + title: l10n.settings_locationGPSEnable, + subtitle: l10n.settings_locationGPSEnableSubtitle, + value: isGPSEnabled, + onChanged: (value) async { + setDialogState(() => isGPSEnabled = value); + if (value) { + await connector.setCustomVar("gps:1"); + } else { + await connector.setCustomVar("gps:0"); + } + }, + ), + ], ], ), actions: [ @@ -510,11 +513,13 @@ class _SettingsScreenState extends State { TextButton( onPressed: () async { Navigator.pop(context); - if (isGPSEnabled) { + + if (hasGPS) { final intervalText = intervalController.text.trim(); if (intervalText.isEmpty) { return; } + final interval = int.tryParse(intervalText); if (interval == null || interval < 60) { if (!context.mounted) return; @@ -525,53 +530,50 @@ class _SettingsScreenState extends State { ); return; } - await connector.setCustomVar("gps:1"); + await connector.setCustomVar("gps_interval:$interval"); await connector.refreshDeviceInfo(); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.settings_locationUpdated)), ); - } else { - final latText = latController.text.trim(); - final lonText = lonController.text.trim(); - if (latText.isEmpty && lonText.isEmpty) { - return; - } + } - final currentLat = connector.selfLatitude; - final currentLon = connector.selfLongitude; - final lat = latText.isNotEmpty - ? double.tryParse(latText) - : currentLat; - final lon = lonText.isNotEmpty - ? double.tryParse(lonText) - : currentLon; - if (lat == null || lon == null) { - if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(l10n.settings_locationBothRequired), - ), - ); - return; - } - if (lat < -90 || lat > 90 || lon < -180 || lon > 180) { - if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_locationInvalid)), - ); - return; - } + final latText = latController.text.trim(); + final lonText = lonController.text.trim(); + if (latText.isEmpty && lonText.isEmpty) { + return; + } - await connector.setCustomVar("gps:0"); - await connector.setNodeLocation(lat: lat, lon: lon); - await connector.refreshDeviceInfo(); + final currentLat = connector.selfLatitude; + final currentLon = connector.selfLongitude; + final lat = latText.isNotEmpty + ? double.tryParse(latText) + : currentLat; + final lon = lonText.isNotEmpty + ? double.tryParse(lonText) + : currentLon; + if (lat == null || lon == null) { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(l10n.settings_locationUpdated)), + SnackBar(content: Text(l10n.settings_locationBothRequired)), ); + return; } + if (lat < -90 || lat > 90 || lon < -180 || lon > 180) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(l10n.settings_locationInvalid)), + ); + return; + } + + await connector.setNodeLocation(lat: lat, lon: lon); + await connector.refreshDeviceInfo(); + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(l10n.settings_locationUpdated)), + ); }, child: Text(l10n.common_save), ), diff --git a/lib/widgets/elements_ui.dart b/lib/widgets/elements_ui.dart new file mode 100644 index 00000000..0c462499 --- /dev/null +++ b/lib/widgets/elements_ui.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +class FeatureToggleRow extends StatefulWidget { + final String title; + final String subtitle; + final bool value; + final bool hasRefreshing; + final bool isRefreshing; + final ValueChanged? onChanged; + final VoidCallback? onRefresh; + final String? refreshTooltip; + + const FeatureToggleRow({ + super.key, + required this.title, + required this.subtitle, + required this.value, + this.hasRefreshing = false, + this.isRefreshing = false, + this.onChanged, + this.onRefresh, + this.refreshTooltip, + }); + + @override + State createState() => _FeatureToggleRow(); +} + +class _FeatureToggleRow extends State { + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: SwitchListTile( + title: Text(widget.title), + subtitle: Text(widget.subtitle), + value: widget.value, + onChanged: widget.onChanged, + contentPadding: EdgeInsets.zero, + ), + ), + if (widget.hasRefreshing) + IconButton( + icon: widget.isRefreshing + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.refresh, size: 20), + onPressed: widget.isRefreshing ? null : widget.onRefresh, + tooltip: widget.refreshTooltip, + visualDensity: VisualDensity.compact, + ), + ], + ); + } +}